loop_in_codes

低调做技术__欢迎移步我的独立博客 codemaro.com 微博 kevinlynx

libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载)

Author : Kevin Lynx

前言

    可以说对于任何网络库(模块)而言,一个缓冲模块都是必不可少的。缓冲模块主要用于缓冲从网络接收到的数据,以及
用户提交的数据(用于发送)。很多时候,我们还需要将网络模块层(非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 (*cb)(struct evbuffer *, size_t, size_t, void *);
    
void *cbarg;
}
;


    libevent的缓冲是一个连续的内存区域,其处理数据的方式(写数据和读数据)更像一个队列操作方式:从后写入,从前
读出。evbuffer分别设置相关指针(一个指标)用于指示读出位置和写入位置。其大致结构如图:

evbuffer_str
    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写数据时,都是将数据写到buffer+off后,buffer到buffer+off之间已被
使用,保存的是有效数据,而orig_buffer和buffer之间则是因为读取数据移动指标而形成的无效区域。
    evbuffer_expand的扩充策略在于,首先判断如果让出orig_buffer和buffer之间的空闲区域是否可以容纳添加的数据,如果
可以,则移动buffer和buffer+off之间的数据到orig_buffer和orig_buffer+off之间(有可能发生内存重叠,所以这里移动调用的
是memmove),然后把新的数据拷贝到orig_buffer+off之后;如果不可以容纳,那么重新分配更大的空间(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)

libevent-1.4.5-stable-vs2005.zip下载

 

posted on 2008-07-16 14:28 Kevin Lynx 阅读(9415) 评论(14)  编辑 收藏 引用 所属分类: 通用编程network

评论

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2008-07-16 15:09 true

写的好!  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2008-08-12 10:32 白云哥

这个libevent的vs2005包很好,谢谢

自己偷懒了一把 :)  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2008-08-25 21:25 weber

写得不错,正在做基于libevent的项目, 一起交流. qq群:64559783  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2008-10-23 18:07 浪迹天涯

libevent用于改造网络模型需要了解哪些知识?  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载)[未登录] 2008-10-23 20:43 Kevin Lynx

@浪迹天涯
改造网络模型?不清楚。我只知道使用别人的库。- -|  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2008-12-09 18:42 vcclass

不错,分析的很好,很实用。libevent相对于ACE来说轻量级多了,ACE 学习曲线比较陡峭,不建议初学者学习。libevent里面还是有很多东西值得借鉴的。
ACE用了很多设计模式的思想来封装,如果对设计模式赶兴趣的话可以研究,否则实际意义不是很大。  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载)[未登录] 2009-04-28 20:06 小马

新手请教 evbuffer用在什么地方了 libevent是事件响应模型 但是具体事件处理还是要使用者自己的代码来实现的 不是么  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2009-04-28 22:41 Kevin Lynx

@小马
在我印象里,evbuffer用于缓存逻辑层(即l基于libevent那一层)将要发送的数据,以及缓存从设备(fd)里读取出的数据。
  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载)[未登录] 2009-04-30 17:08 小马

@Kevin Lynx
是不是这样 libevent代码里本身没有用到evbuffer 只是我们在用libevent开发自己的应用的时候可以使用evbuffer ?  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2009-04-30 21:40 Kevin Lynx

@小马
为什么你不打开libevent的源代码搜索下evbuffer呢??  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2009-06-26 21:11 taozzee

请问 libevent 中类型 struct event_list 在哪定义的呢??

在VC6下编译通不过啊。  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2010-05-24 09:09 周江涛

写的好,表达能力强,分析透彻!  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2011-05-07 21:49 dourgulf

其实,这个buffer管理方法效率很差了,涉及很多内存的移动。
其实,很多socket I/O都提供了buffer数组的发送方式,使用这种方式高效而且简单。最新的libevent已经放弃了LZ说的这个buffer管理方法了。  回复  更多评论   

# re: libevent 源码分析:evbuffer缓冲(附带libevent vs2005完整包下载) 2014-05-19 15:53 coderchen

@dourgulf
现在libevent的buffer应该是多个内存块组成的chain,但是由于内存不连续,作为接收缓冲区反序列化的时候,还要多拷贝一次数据。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理