• 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 '
    ', '
    
    ' or '
    ' or '
    '.
    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     //读到
    或者
    
    240     for (i = 0; i < len; i++) {
    241         if (data[i] == '
    ' || data[i] == '
    ')
    242             break;
    243     }
    244     //没读到回车或者换行,退出
    245     if (i == len)
    246         return (NULL);
    247     //分配i+1字节内存,最后结尾
    248     if ((line = malloc(i + 1)) == NULL) {
    249         fprintf(stderr, "%s: out of memory
    ", __func__);
    250         return (NULL);
    251     }
    252     //从data起始地址开始复制i个字节到line中
    253     memcpy(line, data, i);
    254     line[i] = '';
    255 
    256     /*
    257      * Some protocols terminate a line with '
    ', so check for
    258      * that, too.
    259      */
    260     //如果i不是最后一个元素检查是否有
    或者
    。情况有可能有
    ,
    
    ,其中
    
    或者
    
    的情况排除,因为没用。
    261     if ( i < len - 1 ) {
    262         char fch = data[i], sch = data[i+1];
    263 
    264         //情况有可能有
    ,
    
    ,其中
    
    或者
    
    的情况排除,因为没用
    265         /* Drain one more character if needed */
    266         if ( (sch == '
    ' || sch == '
    ') && 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                任意数量的
    和
    
    278 //EVBUFFER_EOL_CRLF                
    或者
    
    279 //EVBUFFER_EOL_CRLF_STRICT        
    
    280 //EVBUFFER_EOL_LF                
    
    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     //任意数量的
    和
    
    299     case EVBUFFER_EOL_ANY:
    300         for (i = 0; i < len; i++) {
    301             if (data[i] == '
    ' || data[i] == '
    ')
    302                 break;
    303         }
    304         if (i == len)
    305             return (NULL);
    306         //
    或者
    开始地址
    307         start_of_eol = data+i;
    308         ++i;
    309         for ( ; i < len; i++) {
    310             if (data[i] != '
    ' && data[i] != '
    ')
    311                 break;
    312         }
    313         //
    或者
    结束地址
    314         end_of_eol = data+i;
    315         break;
    316     //
    或者
    
    317     case EVBUFFER_EOL_CRLF:
    318         //从data起始地址开始前len个字节查找
    字符
    319         end_of_eol = memchr(data, '
    ', len);
    320         //没找到返回NULL
    321         if (!end_of_eol)
    322             return (NULL);
    323         //前一个字符是
    
    324         if (end_of_eol > data && *(end_of_eol-1) == '
    ')
    325             start_of_eol = end_of_eol - 1;
    326         else
    327             start_of_eol = end_of_eol;
    328         //指向
    的下一个字节
    329         end_of_eol++; /*point to one after the LF. */
    330         break;
    331     //
    
    332     case EVBUFFER_EOL_CRLF_STRICT: {
    333         u_char *cp = data;
    334         //一直向前移动找到 "
    "的连续字符。
    335         //如果
    后面不是
    ,++cp,此时cp前面的数据就不用比较了
    336         while ((cp = memchr(cp, '
    ', len-(cp-data)))) {
    337             if (cp < data+len-1 && *(cp+1) == '
    ')
    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     //
    
    351     case EVBUFFER_EOL_LF:
    352         start_of_eol = memchr(data, '
    ', 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带个结束字符 
    366     if ((line = malloc(n_to_copy+1)) == NULL) {
    367         event_warn("%s: out of memory
    ", __func__);
    368         return (NULL);
    369     }
    370     //数据复制到line中
    371     memcpy(line, data, n_to_copy);
    372     line[n_to_copy] = '';
    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 }
  • 相关阅读:
    SQL 语句优化中间表的使用优化
    SQL 语句优化OR 语句优化案例
    浅谈系统优化设计复杂运算放在逻辑层还是在数据库层?
    linux命令综合
    MySQL常用命令
    PHP知识点积累
    [Git] 生成token解决github remote: Support for password authentication was removed on August 13, 2021.
    [uniapp] GOFLY在线客服系统 uniapp增加播放背景音效或者按钮音效
    [Golang]gorm更新数据update 解决值为0时被忽略
    光阴真的是贱(似箭),一不小心就又过一年了
  • 原文地址:https://www.cnblogs.com/nengm1988/p/8073842.html
Copyright © 2020-2023  润新知