libevent中数据缓冲区buffer分析

       很多时候为了应对数据IO的“慢“或者其他原因都需要使用数据缓冲区。对于数据缓冲,我们不陌生,但是对于如何实现这个缓冲区,相信很多时候大家都没有考虑过。今天就通过分析libevent的buffer.c源码,看看libevent是如何实现这个缓冲区的。

       数据缓冲区buffer是libevent中网络IO操作中最先接触数据的容器。

     1. 缓冲区evbuffer结构

 1 struct evbuffer {
 2     //存放数据起始位置
 3     u_char *buffer;
 4 
 5     //buffer起始地址
 6     u_char *orig_buffer;
 7 
 8     //buffer起始地址与数据存放地址的偏移
 9     size_t misalign;
10 
11     //总共buffer的长度
12     size_t totallen;
13 
14     //缓冲区数据长度
15     size_t off;
16 
17     //回调函数
18     void (*cb)(struct evbuffer *, size_t, size_t, void *);
19 
20     //回调需要的参数
21     void *cbarg;
22 };

 2. evbuffer结构图

 3. ebuffer如何变化

     4. 重要的几个函数注释

     1.evbuffer_add

 1 //从data地址开始datlen个字节数据到evbuffer中
 2 int
 3 evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
 4 {    
 5     //                           整个buffer
 6     //|                           totallen                            |
 7     //|--------------|-----------|---------------------------|--------|
 8     //|misalign(偏移) |off(数据区) |datlen(需要加入的数据长度)    |剩余空间  |
 9     //
10     size_t need = buf->misalign + buf->off + datlen;
11     size_t oldoff = buf->off;
12     
13     //如果need大于了总长度,需要调整扩大
14     if (buf->totallen < need) {
15         //evbuffer调整扩大
16         if (evbuffer_expand(buf, datlen) == -1)
17             return (-1);
18     }
19     //将datlen长度的data数据复制到buffer中。
20     memcpy(buf->buffer + buf->off, data, datlen);
21     //复制成功,数据长度增加
22     buf->off += datlen;
23     //datlen不为0且buf有回调函数,调用回调函数,告知缓存变化
24     if (datlen && buf->cb != NULL)
25         (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
26 
27     return (0);
28 }

        2.evbuffer_drain

 1 //drain:使流出;排掉水
 2 //从缓冲区中读出len长度数据。
 3 void
 4 evbuffer_drain(struct evbuffer *buf, size_t len)
 5 {
 6     //记录当前缓冲区中的数据长度
 7     size_t oldoff = buf->off;
 8 
 9     //如果要读出的长度大于数据长度,就读出全部数据
10     if (len >= buf->off) {
11 
12         //                           整个buffer
13         //|                           totallen                            |
14         //|||-------------------------------------------------------------|
15         //|||剩余空间                                                       |
16         //
17 
18         //元素个数清零
19         buf->off = 0;
20         //数据缓冲地址前移到最前面的buf起始位置
21         buf->buffer = buf->orig_buffer;
22         //数据偏移置0
23         buf->misalign = 0;
24         goto done;
25     }
26     //如果读出数据不是全部数据
27 
28     //                           整个buffer
29     //|                           totallen                            |
30     //|--------------|-----------|------------------------------------|
31     //|  misalign    |off(数据区) |         剩余空间                     |
32     //                          | |
33     //                          \ /
34 
35     //                           整个buffer
36     //|                           totallen                            |
37     //|-----------------|--------|------------------------------------|
38     //|  misalign       |off     |         剩余空间                     |
39     //                         
40 
41     //buffer地址前移len
42     buf->buffer += len;
43     //misalign偏移加len
44     buf->misalign += len;
45     //由于读出数据,off减少len个数据
46     buf->off -= len;
47 
48 done:
49     //缓冲区数据长度改变,调用回调函数
50     /* Tell someone about changes in this buffer */
51     if (buf->off != oldoff && buf->cb != NULL)
52         (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
53 
54 }

      3.evbuffer_align

 1 //buf进行重新排列
 2 static void
 3 evbuffer_align(struct evbuffer *buf)
 4 {
 5     //                           整个buffer
 6     //|                           totallen                                   |
 7     //|--------------|-----------|-------------------------------------------|
 8     //|misalign(偏移)|off(数据区)|datlen(需要加入的数据长度),大于totallen         |  
 9     //                          | |
10     //                          \ /
11     //                           整个buffer
12     //|                           totallen                                  |
13     //|-----------|---------------------------------------------------------|
14     //|off(数据区) |datlen(需要加入的数据长度),大于totallen                      |  
15 
16 
17     //缓冲区数据前移
18     //从buf->buffer拷贝off个字节到buf的orig_buffer
19     memmove(buf->orig_buffer, buf->buffer, buf->off);
20 
21     //缓冲区数据起始位置变为buf起始位置
22     buf->buffer = buf->orig_buffer;
23 
24     //偏移置为0
25     buf->misalign = 0;
26 }

      4.evbuffer_expand

 1 /* Expands the available space in the event buffer to at least datlen */
 2 //内存扩展
 3 int
 4 evbuffer_expand(struct evbuffer *buf, size_t datlen)
 5 {
 6     //                           整个buffer
 7     //|                           totallen                                   |
 8     //|--------------|-----------|-------------------------------------------|
 9     //|misalign(偏移) |off(数据区) |datlen(需要加入的数据长度),大于totallen       |  
10     //
11 
12     //首先判断是否需要扩展
13     size_t need = buf->misalign + buf->off + datlen;
14 
15     //如果need小于totallen,无需扩展
16     /* If we can fit all the data, then we don't have to do anything */
17     if (buf->totallen >= need)
18         return (0);
19 
20     /*
21      * If the misalignment fulfills our data needs, we just force an
22      * alignment to happen.  Afterwards, we have enough space.
23      */
24     //如果偏移大于datlen,
25     if (buf->misalign >= datlen) {
26         //buf进行重新排列
27         evbuffer_align(buf);
28     } else {
29         //偏移小于datlen,数据元素大于totallen,需要重新分配内存
30         void *newbuf;
31         size_t length = buf->totallen;
32 
33         //如果length小于256,length设置256
34         if (length < 256)
35             length = 256;
36         //如果length还是小于need,length扩大2倍直到不小于need
37         while (length < need)
38             length <<= 1;
39 
40         //如果有偏移,先重新排列
41         if (buf->orig_buffer != buf->buffer)
42             evbuffer_align(buf);
43         //重新分配内存
44         if ((newbuf = realloc(buf->buffer, length)) == NULL)
45             return (-1);
46         //orig_buffer,buffer都赋值为新地址newbuf
47         buf->orig_buffer = buf->buffer = newbuf;
48         //总长度totallen为length
49         buf->totallen = length;
50     }
51 
52     return (0);
53 }

 5.所有代码注释

  1 /*
  2  * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
  3  * All rights reserved.
  4  *
  5  * Redistribution and use in source and binary forms, with or without
  6  * modification, are permitted provided that the following conditions
  7  * are met:
  8  * 1. Redistributions of source code must retain the above copyright
  9  *    notice, this list of conditions and the following disclaimer.
 10  * 2. Redistributions in binary form must reproduce the above copyright
 11  *    notice, this list of conditions and the following disclaimer in the
 12  *    documentation and/or other materials provided with the distribution.
 13  * 3. The name of the author may not be used to endorse or promote products
 14  *    derived from this software without specific prior written permission.
 15  *
 16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 26  */
 27 
 28 #ifdef HAVE_CONFIG_H
 29 #include "config.h"
 30 #endif
 31 
 32 #ifdef WIN32
 33 #include <winsock2.h>
 34 #include <windows.h>
 35 #endif
 36 
 37 #ifdef HAVE_VASPRINTF
 38 /* If we have vasprintf, we need to define this before we include stdio.h. */
 39 #define _GNU_SOURCE
 40 #endif
 41 
 42 #include <sys/types.h>
 43 
 44 #ifdef HAVE_SYS_TIME_H
 45 #include <sys/time.h>
 46 #endif
 47 
 48 #ifdef HAVE_SYS_IOCTL_H
 49 #include <sys/ioctl.h>
 50 #endif
 51 
 52 #include <assert.h>
 53 #include <errno.h>
 54 #include <stdio.h>
 55 #include <stdlib.h>
 56 #include <string.h>
 57 #ifdef HAVE_STDARG_H
 58 #include <stdarg.h>
 59 #endif
 60 #ifdef HAVE_UNISTD_H
 61 #include <unistd.h>
 62 #endif
 63 
 64 #include "event.h"
 65 #include "config.h"
 66 #include "evutil.h"
 67 #include "./log.h"
 68 
 69 //创建evbuffer
 70 struct evbuffer *
 71 evbuffer_new(void)
 72 {
 73     struct evbuffer *buffer;
 74     
 75     buffer = calloc(1, sizeof(struct evbuffer));
 76 
 77     return (buffer);
 78 }
 79 
 80 //释放evbuffer
 81 void
 82 evbuffer_free(struct evbuffer *buffer)
 83 {
 84     if (buffer->orig_buffer != NULL)
 85         free(buffer->orig_buffer);
 86     free(buffer);
 87 }
 88 
 89 /* 
 90  * This is a destructive add.  The data from one buffer moves into
 91  * the other buffer.
 92  */
 93 
 94 //交换evbuffer
 95 #define SWAP(x,y) do { \
 96     (x)->buffer = (y)->buffer; \
 97     (x)->orig_buffer = (y)->orig_buffer; \
 98     (x)->misalign = (y)->misalign; \
 99     (x)->totallen = (y)->totallen; \
100     (x)->off = (y)->off; \
101 } while (0)
102 
103 //evbuffer数据交换,outhuf与inbuf
104 int
105 evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
106 {
107     int res;
108 
109     //如果outbuf没有数据元素
110     /* Short cut for better performance */
111     if (outbuf->off == 0) {
112         struct evbuffer tmp;
113         size_t oldoff = inbuf->off;
114 
115         //交换缓冲区
116         /* Swap them directly */
117         SWAP(&tmp, outbuf);
118         SWAP(outbuf, inbuf);
119         SWAP(inbuf, &tmp);
120 
121         /* 
122          * Optimization comes with a price; we need to notify the
123          * buffer if necessary of the changes. oldoff is the amount
124          * of data that we transfered from inbuf to outbuf
125          */
126         //如果现在的数据元素长度不等于以前inbuf中的数据元素长度,并且有回调函数的话,
127         //交换后inbuf调用回调函数,告诉现在数据元素长度已经改变等信息
128         if (inbuf->off != oldoff && inbuf->cb != NULL)
129             (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
130         //原来inbuf数据元素个数不为0,且有回调函数。交换后的outbuf调用回调。
131         if (oldoff && outbuf->cb != NULL)
132             (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
133         
134         return (0);
135     }
136     //如果原来的outbuf中有数据元素,把inbuf中的数据元素加入进来
137     res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
138     if (res == 0) {
139         //res为零,成功将inbuf的数据元素加入到outbuf中来,所以可以将inbuf中的数据全部排出清空。
140         /* We drain the input buffer on success */
141         evbuffer_drain(inbuf, inbuf->off);
142     }
143 
144     return (res);
145 }
146 
147 //将数据格式化后添加到buf中
148 int
149 evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
150 {
151     char *buffer;
152     size_t space;
153     size_t oldoff = buf->off;
154     int sz;
155     va_list aq;
156 
157     /* make sure that at least some space is available */
158     //确保至少有一些空间,这里看看有没有64字节容量。
159     evbuffer_expand(buf, 64);
160     for (;;) {
161         size_t used = buf->misalign + buf->off;
162         buffer = (char *)buf->buffer + buf->off;
163         assert(buf->totallen >= used);
164         space = buf->totallen - used;
165 
166 #ifndef va_copy
167 #define    va_copy(dst, src)    memcpy(&(dst), &(src), sizeof(va_list))
168 #endif
169         va_copy(aq, ap);
170         //返回写入buffer后面的字节数
171         sz = evutil_vsnprintf(buffer, space, fmt, aq);
172 
173         va_end(aq);
174 
175         if (sz < 0)
176             return (-1);
177         //如果格式化的数据字节数小于剩余的容量
178         if ((size_t)sz < space) {
179             buf->off += sz;
180             if (buf->cb != NULL)
181                 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
182             return (sz);
183         }
184         //到这边说明容量不够,需要调整
185         if (evbuffer_expand(buf, sz + 1) == -1)
186             return (-1);
187 
188     }
189     /* NOTREACHED */
190 }
191 
192 //将数据格式化后添加到buf中
193 int
194 evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
195 {
196     int res = -1;
197     va_list ap;
198 
199     va_start(ap, fmt);
200     res = evbuffer_add_vprintf(buf, fmt, ap);
201     va_end(ap);
202 
203     return (res);
204 }
205 
206 /* Reads data from an event buffer and drains the bytes read */
207 //从buf中读出datlen个字节存到data开始地址中
208 int
209 evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
210 {
211     size_t nread = datlen;
212     //最多只能读出缓冲区中所有数据
213     if (nread >= buf->off)
214         nread = buf->off;
215     //从buf->buffer地址的起始位置拷贝nread个字节到data开始的地址
216     memcpy(data, buf->buffer, nread);
217     //将nread个字节的数据排出缓冲区
218     evbuffer_drain(buf, nread);
219     
220     return (nread);
221 }
222 
223 /*
224  * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
225  * The returned buffer needs to be freed by the called.
226  */
227 
228 //从缓冲区中读出一行
229 char *
230 evbuffer_readline(struct evbuffer *buffer)
231 {
232     //缓冲数据区的起始地址
233     u_char *data = EVBUFFER_DATA(buffer);
234     //缓冲区数据长度
235     size_t len = EVBUFFER_LENGTH(buffer);
236     char *line;
237     unsigned int i;
238 
239     //读到\r或者\n
240     for (i = 0; i < len; i++) {
241         if (data[i] == '\r' || data[i] == '\n')
242             break;
243     }
244     //没读到回车或者换行,退出
245     if (i == len)
246         return (NULL);
247     //分配i+1字节内存,最后\0结尾
248     if ((line = malloc(i + 1)) == NULL) {
249         fprintf(stderr, "%s: out of memory\n", __func__);
250         return (NULL);
251     }
252     //从data起始地址开始复制i个字节到line中
253     memcpy(line, data, i);
254     line[i] = '\0';
255 
256     /*
257      * Some protocols terminate a line with '\r\n', so check for
258      * that, too.
259      */
260     //如果i不是最后一个元素检查是否有\n或者\r。情况有可能有\r\n,\n\r,其中\r\r或者\n\n的情况排除,因为没用。
261     if ( i < len - 1 ) {
262         char fch = data[i], sch = data[i+1];
263 
264         //情况有可能有\r\n,\n\r,其中\r\r或者\n\n的情况排除,因为没用
265         /* Drain one more character if needed */
266         if ( (sch == '\r' || sch == '\n') && sch != fch )
267             i += 1;
268     }
269 
270     //将读取到的数据清除出缓冲区,i是序号从0开始,所以长度为i+1
271     evbuffer_drain(buffer, i + 1);
272 
273     return (line);
274 }
275 
276 //从缓冲区中读出一行,结束方式有4种
277 //EVBUFFER_EOL_ANY                任意数量的\r和\n
278 //EVBUFFER_EOL_CRLF                \n或者\r\n
279 //EVBUFFER_EOL_CRLF_STRICT        \r\n
280 //EVBUFFER_EOL_LF                \n
281 char *
282 evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
283         enum evbuffer_eol_style eol_style)
284 {
285     u_char *data = EVBUFFER_DATA(buffer);
286     u_char *start_of_eol, *end_of_eol;
287     size_t len = EVBUFFER_LENGTH(buffer);
288     char *line;
289     unsigned int i, n_to_copy, n_to_drain;
290 
291     //如果n_read_out不为NULL,初始化为0
292     if (n_read_out)
293         *n_read_out = 0;
294 
295     /* depending on eol_style, set start_of_eol to the first character
296      * in the newline, and end_of_eol to one after the last character. */
297     switch (eol_style) {
298     //任意数量的\r和\n
299     case EVBUFFER_EOL_ANY:
300         for (i = 0; i < len; i++) {
301             if (data[i] == '\r' || data[i] == '\n')
302                 break;
303         }
304         if (i == len)
305             return (NULL);
306         //\r或者\n开始地址
307         start_of_eol = data+i;
308         ++i;
309         for ( ; i < len; i++) {
310             if (data[i] != '\r' && data[i] != '\n')
311                 break;
312         }
313         //\r或者\n结束地址
314         end_of_eol = data+i;
315         break;
316     //\n或者\r\n
317     case EVBUFFER_EOL_CRLF:
318         //从data起始地址开始前len个字节查找\n字符
319         end_of_eol = memchr(data, '\n', len);
320         //没找到返回NULL
321         if (!end_of_eol)
322             return (NULL);
323         //前一个字符是\r
324         if (end_of_eol > data && *(end_of_eol-1) == '\r')
325             start_of_eol = end_of_eol - 1;
326         else
327             start_of_eol = end_of_eol;
328         //指向\n的下一个字节
329         end_of_eol++; /*point to one after the LF. */
330         break;
331     //\r\n
332     case EVBUFFER_EOL_CRLF_STRICT: {
333         u_char *cp = data;
334         //一直向前移动找到 "\r\n"的连续字符。
335         //如果\r后面不是\n,++cp,此时cp前面的数据就不用比较了
336         while ((cp = memchr(cp, '\r', len-(cp-data)))) {
337             if (cp < data+len-1 && *(cp+1) == '\n')
338                 break;
339             if (++cp >= data+len) {
340                 cp = NULL;
341                 break;
342             }
343         }
344         if (!cp)
345             return (NULL);
346         start_of_eol = cp;
347         end_of_eol = cp+2;
348         break;
349     }
350     //\n
351     case EVBUFFER_EOL_LF:
352         start_of_eol = memchr(data, '\n', len);
353         if (!start_of_eol)
354             return (NULL);
355         end_of_eol = start_of_eol + 1;
356         break;
357     default:
358         return (NULL);
359     }
360     //数据区有多少个元素
361     n_to_copy = start_of_eol - data;
362     //数据缓冲区一共要排出的元素
363     n_to_drain = end_of_eol - data;
364 
365     //n_to_copy+1带个结束字符 \0
366     if ((line = malloc(n_to_copy+1)) == NULL) {
367         event_warn("%s: out of memory\n", __func__);
368         return (NULL);
369     }
370     //数据复制到line中
371     memcpy(line, data, n_to_copy);
372     line[n_to_copy] = '\0';
373 
374     //缓冲区清空读出的数据和末尾的结束符号
375     evbuffer_drain(buffer, n_to_drain);
376     //如果n_read_out不为NULL,返回读出的字符串字节数
377     if (n_read_out)
378         *n_read_out = (size_t)n_to_copy;
379 
380     return (line);
381 }
382 
383 /* Adds data to an event buffer */
384 
385 //buf进行重新排列
386 static void
387 evbuffer_align(struct evbuffer *buf)
388 {
389     //                           整个buffer
390     //|                           totallen                                   |
391     //|--------------|-----------|-------------------------------------------|
392     //|misalign(偏移) |off(数据区) |datlen(需要加入的数据长度),大于totallen       |  
393     //                          | |
394     //                          \ /
395     //                           整个buffer
396     //|                           totallen                                  |
397     //|-----------|---------------------------------------------------------|
398     //|off(数据区) |datlen(需要加入的数据长度),大于totallen                      |  
399 
400 
401     //缓冲区数据前移
402     //从buf->buffer拷贝off个字节到buf的orig_buffer
403     memmove(buf->orig_buffer, buf->buffer, buf->off);
404 
405     //缓冲区数据起始位置变为buf起始位置
406     buf->buffer = buf->orig_buffer;
407 
408     //偏移置为0
409     buf->misalign = 0;
410 }
411 
412 /* Expands the available space in the event buffer to at least datlen */
413 //内存扩展
414 int
415 evbuffer_expand(struct evbuffer *buf, size_t datlen)
416 {
417     //                           整个buffer
418     //|                           totallen                                   |
419     //|--------------|-----------|-------------------------------------------|
420     //|misalign(偏移) |off(数据区) |datlen(需要加入的数据长度),大于totallen       |  
421     //
422 
423     //首先判断是否需要扩展
424     size_t need = buf->misalign + buf->off + datlen;
425 
426     //如果need小于totallen,无需扩展
427     /* If we can fit all the data, then we don't have to do anything */
428     if (buf->totallen >= need)
429         return (0);
430 
431     /*
432      * If the misalignment fulfills our data needs, we just force an
433      * alignment to happen.  Afterwards, we have enough space.
434      */
435     //如果偏移大于datlen,
436     if (buf->misalign >= datlen) {
437         //buf进行重新排列
438         evbuffer_align(buf);
439     } else {
440         //偏移小于datlen,数据元素大于totallen,需要重新分配内存
441         void *newbuf;
442         size_t length = buf->totallen;
443 
444         //如果length小于256,length设置256
445         if (length < 256)
446             length = 256;
447         //如果length还是小于need,length扩大2倍直到不小于need
448         while (length < need)
449             length <<= 1;
450 
451         //如果有偏移,先重新排列
452         if (buf->orig_buffer != buf->buffer)
453             evbuffer_align(buf);
454         //重新分配内存
455         if ((newbuf = realloc(buf->buffer, length)) == NULL)
456             return (-1);
457         //orig_buffer,buffer都赋值为新地址newbuf
458         buf->orig_buffer = buf->buffer = newbuf;
459         //总长度totallen为length
460         buf->totallen = length;
461     }
462 
463     return (0);
464 }
465 
466 //从data地址开始datlen个字节数据到evbuffer中
467 int
468 evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
469 {    
470     //                           整个buffer
471     //|                           totallen                            |
472     //|--------------|-----------|---------------------------|--------|
473     //|misalign(偏移) |off(数据区) |datlen(需要加入的数据长度)    |剩余空间  |
474     //
475     size_t need = buf->misalign + buf->off + datlen;
476     size_t oldoff = buf->off;
477     
478     //如果need大于了总长度,需要调整扩大
479     if (buf->totallen < need) {
480         //evbuffer调整扩大
481         if (evbuffer_expand(buf, datlen) == -1)
482             return (-1);
483     }
484     //将datlen长度的data数据复制到buffer中。
485     memcpy(buf->buffer + buf->off, data, datlen);
486     //复制成功,数据长度增加
487     buf->off += datlen;
488     //datlen不为0且buf有回调函数,调用回调函数,告知缓存变化
489     if (datlen && buf->cb != NULL)
490         (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
491 
492     return (0);
493 }
494 
495 //drain:使流出;排掉水
496 //从缓冲区中读出len长度数据。
497 void
498 evbuffer_drain(struct evbuffer *buf, size_t len)
499 {
500     //记录当前缓冲区中的数据长度
501     size_t oldoff = buf->off;
502 
503     //如果要读出的长度大于数据长度,就读出全部数据
504     if (len >= buf->off) {
505 
506         //                           整个buffer
507         //|                           totallen                            |
508         //|||-------------------------------------------------------------|
509         //|||剩余空间                                                       |
510         //
511 
512         //元素个数清零
513         buf->off = 0;
514         //数据缓冲地址前移到最前面的buf起始位置
515         buf->buffer = buf->orig_buffer;
516         //数据偏移置0
517         buf->misalign = 0;
518         goto done;
519     }
520     //如果读出数据不是全部数据
521 
522     //                           整个buffer
523     //|                           totallen                            |
524     //|--------------|-----------|------------------------------------|
525     //|  misalign    |off(数据区) |         剩余空间                     |
526     //                          | |
527     //                          \ /
528 
529     //                           整个buffer
530     //|                           totallen                            |
531     //|-----------------|--------|------------------------------------|
532     //|  misalign       |off     |         剩余空间                     |
533     //                         
534 
535     //buffer地址前移len
536     buf->buffer += len;
537     //misalign偏移加len
538     buf->misalign += len;
539     //由于读出数据,off减少len个数据
540     buf->off -= len;
541 
542 done:
543     //缓冲区数据长度改变,调用回调函数
544     /* Tell someone about changes in this buffer */
545     if (buf->off != oldoff && buf->cb != NULL)
546         (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
547 
548 }
549 
550 /*
551  * Reads data from a file descriptor into a buffer.
552  */
553 
554 #define EVBUFFER_MAX_READ    4096
555 //从文件描述符中读取数据到buffer中
556 int
557 evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
558 {
559     u_char *p;
560     size_t oldoff = buf->off;
561     int n = EVBUFFER_MAX_READ;
562 
563 #if defined(FIONREAD)
564 #ifdef WIN32
565     long lng = n;
566     if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) <= 0) {
567 #else
568     if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
569 #endif
570         n = EVBUFFER_MAX_READ;
571     } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
572         /*
573          * It's possible that a lot of data is available for
574          * reading.  We do not want to exhaust resources
575          * before the reader has a chance to do something
576          * about it.  If the reader does not tell us how much
577          * data we should read, we artifically limit it.
578          */
579         if ((size_t)n > buf->totallen << 2)
580             n = buf->totallen << 2;
581         if (n < EVBUFFER_MAX_READ)
582             n = EVBUFFER_MAX_READ;
583     }
584 #endif    
585     //buffer最多读EVBUFFER_MAX_READ个字节
586     if (howmuch < 0 || howmuch > n)
587         howmuch = n;
588 
589     /* If we don't have FIONREAD, we might waste some space here */
590     //如果需要读的howmuch个字节数据,首先扩展buffer。因为我们没有FIONREAD参数,有可能howmuch很大,所以可能
591     //会浪费内存
592     if (evbuffer_expand(buf, howmuch) == -1)
593         return (-1);
594 
595     /* We can append new data at this point */
596     //读入数据的起始位置
597     p = buf->buffer + buf->off;
598 
599     //读数据
600 #ifndef WIN32
601     n = read(fd, p, howmuch);
602 #else
603     n = recv(fd, p, howmuch, 0);
604 #endif
605     if (n == -1)
606         return (-1);
607     if (n == 0)
608         return (0);
609 
610     //缓冲区数据长度+n
611     buf->off += n;
612 
613     //缓冲区数据改变,有回调,调用回调
614     /* Tell someone about changes in this buffer */
615     if (buf->off != oldoff && buf->cb != NULL)
616         (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
617 
618     return (n);
619 }
620 
621 //将缓冲区数据读出,写入到fd文件描述符对应的文件中
622 int
623 evbuffer_write(struct evbuffer *buffer, int fd)
624 {
625     int n;
626     //从buffer开始,将off个字节写入fd
627 #ifndef WIN32
628     n = write(fd, buffer->buffer, buffer->off);
629 #else
630     n = send(fd, buffer->buffer, buffer->off, 0);
631 #endif
632     //发生错误
633     if (n == -1)
634         return (-1);
635     //关闭写
636     if (n == 0)
637         return (0);
638     //写入fd成功,将缓冲区中排出已经写入的n个字节
639     evbuffer_drain(buffer, n);
640 
641     return (n);
642 }
643 //从buffer中查找从what地址开始的长度为len的字符串
644 u_char *
645 evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
646 {
647     u_char *search = buffer->buffer, *end = search + buffer->off;
648     u_char *p;
649     //从search所指内存区域的前end - search个字节查找字符*what(首字符)
650     while (search < end &&
651         (p = memchr(search, *what, end - search)) != NULL) {
652         //当前位置p+len大于end,已经不可能找到从what地址开始的长度为len的字符串,跳出
653         if (p + len > end)
654             break;
655         //比较p开始的内存和what开始的内存区域的前len个字节
656         if (memcmp(p, what, len) == 0)
657             return (p);
658         //p开始的内存和what开始的内存区域的前len个字节不匹配,地址p+1,继续查找
659         search = p + 1;
660     }
661 
662     return (NULL);
663 }
664 
665 //设置回调函数和回调参数
666 void evbuffer_setcb(struct evbuffer *buffer,
667     void (*cb)(struct evbuffer *, size_t, size_t, void *),
668     void *cbarg)
669 {
670     //设置回调函数
671     buffer->cb = cb;
672 
673     //设置回调参数
674     buffer->cbarg = cbarg;
675 }

 

posted on 2017-12-20 16:03  nengm  阅读(3224)  评论(0编辑  收藏  举报

导航