很多时候为了应对数据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 }