【VC++开源代码栏目提醒】:网学会员VC++开源代码为您提供libevent 源码分析:evbuffer缓冲 - 计算机教材参考,解决您在libevent 源码分析:evbuffer缓冲 - 计算机教材学习中工作中的难题,参考学习。
前言 可以说对于任何网络库模块而言,一个缓冲模块都是必不可少的。
缓冲模块主要用于缓冲从
网络接收到的数据,以及 用户提交的数据用于发送。
很多时候,我们还需要将网络模块层非TCP层的这些缓冲数据拷贝到用户层,而这些内存拷贝 都会消耗时间。
在这里,我简要分析下libevent的相关
代码event.h和buffer.c。
结构 关于libevent的缓冲模块,主要就是围绕evbuffer结构体展开。
先看下evbuffer的定义: ///event.h/ struct evbuffer u_char buffer u_char orig_buffer size_t misalign size_t totallen size_t off void cbstruct evbuffer size_t size_t void void cbarg libevent的缓冲是一个连续的内存区域,其处理数据的方式写数据和读数据更像一个队列操作方式:从后写入,从前 读出。
evbuffer分别设置相关指针一个指标用于指示读出位置和写入位置。
其大致结构如图: orig_buffer指向由realloc分配的连续内存区域,buffer指向有效数据的内存区域,totallen表示orig_buffer指向的内存 区域的大小,
misalign表示buffer相对于orig_buffer的偏移,off表示有效数据的长度。
实际运作 这里我将结合具体的
代码分析libevent是如何操作上面那个队列式的evbuffer的,先看一些辅助函数: evbuffer_drain: 该函数主要操作一些指标,当每次从evbuffer里读取数据时,libevent便会将buffer指针后移,同时增大misalign,减小off, 而该函数正是做这件事的。
说白了,该函数就是用于调整缓冲队列的前向指标。
evbuffer_expand: 该函数用于扩充evbuffer的容量。
每次向evbuffer写数据时,都是将数据写到bufferoff后,buffer到bufferoff之间已被 使用,保存的是有效数据,而orig_buffer和buffer之间则是因为读取数据移动指标而形成的无效区域。
evbuffer_expand的扩充策略在于,首先判断如果让出orig_buffer和buffer之间的空闲区域是否可以容纳添加的数据,如果 可以,则移动buffer和bufferoff之间的数据到orig_buffer和orig_bufferoff之间有可能发生内存重叠,所以这里移动调用的 是memmove,然后把新的数据拷贝到orig_bufferoff之后;如果不可以容纳,那么重新分配更大的空间realloc,同样会移动 数据。
扩充内存的策略为:确保新的内存区域最小尺寸为256,且以乘以2的方式逐步扩大256、512、1024、...。
了解了以上两个函数,看其他函数就比较简单了。
可以看看具体的读数据和写数据: evbuffer_add: 该函数用于添加一段用户数据到evbuffer中。
很简单,就是先判断是否有足够的空闲内存,如果没有则调用evbuffer_expand 扩充之,然后直接memcpy,更新off指标。
evbuffer_remove: 该函数用于将evbuffer中的数据复制给用户空间读数据。
简单地将数据memcpy,然后调用evbuffer_drain移动相关指标。
其他 回过头看看libevent的evbuffer其实是非常简单的跟我那个kl_net里的buffer一样,不知道其他人有没有更优的缓冲管理
方案。
evbuffer还提供了两个函数:evbuffer_write和evbuffer_read,用于直接在套接字其他文件描述符上写/读数据。
另外,关于libevent,因为官方提供的
VC工程文件有
问题,很多人在windows下编译不过。
金庆曾提供过一种方法。
其实主要 就是修改event-config.h文件,修改编译相关配置。
这里我也提供一个解决步骤,顺便提供完整包下载: 1. vs2005打开libevent.dsw,转换四个工程event_test libevent signal_test time_test 2. 删除libevent项目中所有的文件,重新添加文件,文件
列表如下: buffer.c evbuffer.c evdns.c evdns.h event.c event.h event_tagging.c event-config.h event-internal.h evhttp.h evrpc.h evrpc.c evrpc-internal.h evsignal.h evutil.c evutil.h http.c http-internal.h log.c log.h min_heap.h strlcpy.c strlcpy-internal.h tree.h win32.c config.h signal.c 3. 替换event-config.h,使用libevent-iocp中的 4. 项目设置里添加HAVE_CONFIG_H预处理宏 5. 修改win32.c中win32_init函数,加入WSAStartup函数,类似于: WSADATA wd int err struct win32op winop size_t size if err WSAStartup MAKEWORD 2 2 wd 0 event_err 1 winsock startup failed : d err 6. 修改win32.c中win32_dealloc函数,在函数末尾加上WSACleanup的调用: WSACleanup 6. 至此libevent编译成功; 7. 几个例子
程序,只需要加入HAVE_CONFIG_H预处理宏,以及连接ws2_32.lib即可; time_test需要修改time-test.c文件,即在包含event.h前包含windows.h