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

本文详细剖析了libevent缓冲模块的实现原理,包括evbuffer结构体定义、内存管理策略及核心函数evbuffer_drain、evbuffer_expand等的运作机制。此外,还介绍了libevent在Windows平台上的编译解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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下载

  

libevent是一个事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。著名分布式缓存软件memcached也是libevent based,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。 编辑本段 详细   编译库代码,编译脚本会判断OS支持哪种类型的事件机制(select、epoll或kqueue),然后条件编译相应代码,供上层使用的接口仍然是保持统一的(否则也不能所谓的跨平台了)。在linux redhat as 4 u 2 上编译相当容易,configure以后make,make install就可以了,windows上编译似乎有点小麻烦,不过稍微改点东西也就通过了。   从代码中看,libevent支持用户使用三种类型的事件,分别是网络IO、定时器、信号三种,在定时器的实现上使用了RB tree的数据结构,以达到高效查找、排序、删除定时器的目的,网络IO上,主要关注了一下linux上的epoll(因为目前的开发主要在linux平台),结果发现libevent的epoll居然用的EPOLLLT,水平触发的方式用起来比较方便,不容易出错,但是在效率上可能比EPOLLET要低一些。   跟网络无关的,libevent也有一些缓冲区管理的函数,而且是c风格的函数,实用性不是太大。libevent没有提供缓存的函数。   虽然libevent实用上的价值不大,但它提供的接口形式还是不错的,实现类似的lib的时候仍然是可以参考的。   Libevent定时器的数据结构自version 1.4起已由红黑树改为最小堆(Min Heap),以提高效率;网络IO和信号的数据结构采用了双向链表(TAILQ)。在实现上主要有3种链表: EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEOUT,一个ev在这3种链表之间被插入或删除,处于EVLIST_ACTIVE链表中的ev最后将会被调度执行。   Libevent提供了DNS,HTTP Server,RPC等组件,HTTP Server可以说是Libevent的经典应用。从http.c可看到Libevent的很多标准写法。写非阻塞式的HTTP Server很容易将socket处理与HTTP协议处理纠缠在一起,Libevent在这点上似乎也有值得推敲的地方。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值