分类:
2010-04-02 10:31:25
Libevent:evbuffer缓冲区分析
在开发网络程序的时候,特别是TCP基于字节流的数据,需要从字节流数据中解析出自己的通讯协议,比如读一行数据:我们每次调用read函数的时候指定了我们期望读多少数据,但这个数据并不一定正好能读到‘\n’,这个时候就需要借助一个缓冲区来保存多余的数据,以便于和下一次读到的数据合并在一起继续分析。Evbuffer就是提供了这样一个缓冲区。
关于libevent的缓冲模块,主要就是围绕evbuffer结构体展开。先看下evbuffer的定义:
|
下面简单介绍一下evbuffer提供的 API,我所使用的libevent版本是1.4.10-stable:
|
动态分配一个struct evbuffer结构,需要调用evbuffer_free释放内存。
|
释放buffer所占用的内存。
|
将data追加到evbuffer中
先判断缓冲区的大小是否可以容纳的下datlen大小,
如果不能,则使用evbuffer_expand扩充容量。然后将data追加到evbuffer->buffer + evbuffer->off后。 并且更新有效缓冲区长度off。
如果datlen > 0, 并且设置了回调函数,则调用回调函数
返回值:成功返回0,失败返回-1。
|
移动数据从一个evbuffer到另一个evbuffer。
实际上还是调用了evbuffer_add添加数据到outbuf中。但会清除inbuf中的数据。
返回值:成功返回0, 失败返回-1。
|
添加一个格式化的字符串到evbuffer尾部。
|
添加一个va_list格式的字符串到evbuffer尾部。
|
从evbuffer起始位置删除指定长度len字节数据
如果len的长度大于等于缓冲区的off的长度,则表明缓冲区的数据都被清空。
如果缓冲区发生变化,并且设置了回调函数,则调用回调函数。
|
该函数用于扩充evbuffer的容量。每次向evbuffer写数据时,都是将数据写到buffer+off后,buffer到buffer+off之间已被使用,保存的是有效数据,而orig_buffer和buffer之间则是因为读取数据移动指针而形成的无效区域。
evbuffer_expand的扩充策略在于:
1,计算出加上datlen后需要的缓冲区大小need
2, 判断当前缓冲区的长度是否可以容纳的下need大小,如果可以则不需要改变缓冲区的大小,直接返回。
3,如果当前缓冲哦你去的长度容纳不下need大小,则判断orig_buffer和buffer之间的空闲区域是否可以容纳添加的数据,如果
可以,则移动buffer和buffer+off之间的数据到orig_buffer和orig_buffer+off之间,然后把新的数据拷贝到orig_buffer+off之后;
4,如果misalign不可以容纳,那么重新分配更大的空间(realloc),同样会移动数据。
扩充内存的策略为:确保新的内存区域最小尺寸为256,且以乘以2的方式逐步扩大(256、512、1024、...)。
返回值:成功返回0, 失败返回-1。
|
查找缓冲区中是否存在指定的字符串what。
注意这里使用的是u_char类型,说明有可能查找的数据不是以’\0’结尾
如果存在返回指向字符串what的指针,没有则返回NULL。
|
调用read/recv函数,从文件描述符fd上读取数据到evbuffer中。如果缓冲区不够,调用evbuffer_expand扩充缓冲区。
|
把缓冲区中的数据,调用send/write函数写入文件描述符fd上, 如果send/write函数写入的字节数大于0,则调用evbuffer_drain删除已写的数据。
|
读取数据以"\r\n","\n\r",
"\r" 或者 "\n"结尾。
返回动态分配内存,需要调用者自己使用free来释放内存。返回一个以“\0”结尾的字符串。
|
将evbuffer缓冲区中的数据读到data中, 最多读datlen字节。如果缓冲区里的数据小于datlen,则拷贝缓冲区中全部数据。
然后调用evbuffer_drain删除已读数据。
|
设置回调函数。当缓冲区中发生变化时, 调用设置的回调函数。
Evbuffer提供的API已经全部介绍完毕,接下来我们通过一个实例进一步学习如何使用evbuffer, 想要使用evbuffer,系统里必须已经安装了libevent。
例子代码如下:evbuffer-test.c
|
其中使用assert断言来测试是否达到我们的预期,如果assert失败,程序会被中断,并且输出类似的错误信息:
[zhanghua@localhost test]$ ./evbuffer-test evbuffer-test: evbuffer-test.c:31: main: Assertion `buff->off == 2' failed. Aborted (core dumped) |
如果程序所有assert 全部达到我们的预期,程序会输出”OK”。
我们使用如下指令编译程序:
gcc -I/home/zhanghua/project/athena/third_party/Linux/2.6-kernal/libevent-1.4.10-stable/include/ evbuffer-test.c -o evbuffer-test -L /home/zhanghua/project/athena/third_party/Linux/2.6-kernal/libevent-1.4.10-stable/lib –levent |
其中需要说明的是 –I –L后面的路径是libevent 头文件和动态库所在的路径,这个需要和自己实际工作环境做调整。
-levent 是我们需要链接libevent 的动态库。
执行程序:
[zhanghua@localhost test]$ ./evbuffer-test ok |
到这里evbuffer就简单的介绍完了,已经感觉到evbuffer的实用和强大了吧,在这里感谢开源者们提供众多优秀的代码供我们学习和使用。