libevent 源码深度剖析
张亮
Email: sparling.liang@hotmail.com
1
回想刚开始写时,就冠以“深度剖析”的名称,也是为了给自己一些压力,以期能写好
这一系列文章,对 libevent 源代码的各方面作详细的分析;现在看来也算是达到了最初的目
的。希望能给学习和使用 libevent 的朋友们有所帮助。
Email:sparkling.liang@hotmail.com
张亮
2
目录
libevent源码深度剖析......................................................................................................................1
目录 ..................................................................................................................................................3
一 序幕.............................................................................................................................................5
1 前言...............................................................................................................................5
2 Libevent简介 .................................................................................................................5
3 学习的好处...................................................................................................................5
二Reactor模式 ..................................................................................................................................6
1 Reactor的事件处理机制 ...............................................................................................6
2 Reactor模式的优点 .......................................................................................................6
3 Reactor模式框架 ...........................................................................................................6
4 Reactor事件处理流程 ...................................................................................................8
5 小结...............................................................................................................................9
三 基本使用场景和事件流程.......................................................................................................10
1 前言.............................................................................................................................10
2 基本应用场景.............................................................................................................10
3 实例代码.....................................................................................................................11
4 事件处理流程.............................................................................................................11
5 小结.............................................................................................................................12
四 libevent源代码文件组织..........................................................................................................13
1 前言.............................................................................................................................13
2 源代码组织结构.........................................................................................................13
3 小结.............................................................................................................................14
五 libevent的核心:事件event .....................................................................................................15
1 libevent的核心-event...................................................................................................15
2 libevent对event的管理 ................................................................................................16
3 事件设置的接口函数.................................................................................................17
4 小结.............................................................................................................................18
六 初见事件处理框架...................................................................................................................19
1 事件处理框架-event_base..........................................................................................19
2 创建和初始化event_base...........................................................................................20
3 接口函数.....................................................................................................................20
4 小节.............................................................................................................................23
七 事件主循环...............................................................................................................................24
1 阶段性的胜利.............................................................................................................24
2 事件处理主循环.........................................................................................................24
3 I/O和Timer事件的统一...............................................................................................27
4 I/O和Signal事件的统一 ..............................................................................................27
5 小节.............................................................................................................................27
八 集成信号处理...........................................................................................................................28
1 集成策略——使用socket pair ...................................................................................28
3
2 集成到事件主循环——通知event_base ...................................................................29
4 evsignal_info结构体....................................................................................................30
5 注册、注销signal事件 ...............................................................................................30
5 小节.............................................................................................................................31
九 集成定时器事件.......................................................................................................................32
1 集成到事件主循环.....................................................................................................32
2 Timer小根堆 ................................................................................................................33
3 小节.............................................................................................................................34
十 支持I/O多路复用技术 .............................................................................................................35
1 统一的关键.................................................................................................................35
2 设置I/O demultiplex机制 ...........................................................................................35
3 小节.............................................................................................................................37
十一 时间管理...............................................................................................................................38
1 初始化检测.................................................................................................................38
2 时间缓存.....................................................................................................................38
3 时间校正.....................................................................................................................40
4 小节.............................................................................................................................41
十二 让libevent支持多线程..........................................................................................................42
1 错误使用示例.............................................................................................................42
2 支持多线程的几种模式.............................................................................................42
3 例子——memcached..................................................................................................43
4 小节.............................................................................................................................44
4
一 序幕
1 前言
Libevent 是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不
少。写这一系列文章的用意在于,一则分享心得;二则对 libevent 代码和设计思想做系统的、
更深层次的分析,写出来,也可供后来者参考。
附带一句:Libevent 是用 c 语言编写的(MS 大牛们都偏爱 c 语言哪),而且几乎是无处
不函数指针,学习其源代码也需要相当的 c 语言基础。
2 Libevent 简介
上来当然要先夸奖啦,Libevent 有几个显著的亮点:
事件驱动(event-driven),高性能;
轻量级,专注于网络,不如 ACE 那么臃肿庞大;
源代码相当精炼、易读;
跨平台,支持 Windows、Linux、*BSD 和 Mac Os;
支持多种 I/O 多路复用技术, epoll、poll、dev/poll、select 和 kqueue 等;
支持 I/O,定时器和信号等事件;
注册事件优先级;
Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、Vomit、Nylon、Netchat
等等。
Libevent 当前的最新稳定版是 1.4.13;这也是本文参照的版本。
3 学习的好处
学习 libevent 有助于提升程序设计功力,除了网络程序设计方面外,Libevent 的代码里
有很多有用的设计技巧和基础数据结构,比如信息隐藏、函数指针、c 语言的多态支持、链
表和堆等等,都有助于提升自身的程序功力。
程序设计不止要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。只对
libevent 本身的框架大概了解,那或许仅仅是一知半解,不深入代码分析,就难以了解其设
计的精巧之处,也就难以为自己所用。
事实上 Libevent 本身就是一个典型的 Reactor 模型,理解 Reactor 模式是理解 libevent
的基石;因此下一节将介绍典型的事件驱动设计模式——Reactor 模式。
参考资料:
Libevent: http://monkey.org/~provos/libevent/
5
二 Reactor 模式
前面讲到,整个 libevent 本身就是一个 Reactor,因此本节将专门对 Reactor 模式进行必
要的介绍,并列出 libevnet 中的几个重要组件和 Reactor 的对应关系,在后面的章节中可能
还会提到本节介绍的基本概念。
1 Reactor 的事件处理机制
首先来回想一下普通函数调用的机制:程序调用某函数函数执行,程序等待函数将
结果和控制权返回给程序程序继续处理。
Reactor 释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用
程序不是主动的调用某个 API 完成处理,而是恰恰相反,Reactor 逆置了事件处理流程,应
用程序需要提供相应的接口并注册到 Reactor 上,如果相应的时间发生,Reactor 将主动调用
应用程序注册的接口,这些接口又称为“回调函数”。使用 Libevent 也是想 Libevent 框架注
册相应的事件和回调函数;当这些时间发声时,Libevent 会调用这些回调函数处理相应的事
件(I/O 读写、定时和信号)。
用“好莱坞原则”来形容 Reactor 再合适不过了:不要打电话给我们,我们会打电话通
知你。
举个例子:你去应聘某 xx 公司,面试结束后。
“普通函数调用机制”公司 HR 比较懒,不会记你的联系方式,那怎么办呢,你只能面
试完后自己打电话去问结果;有没有被录取啊,还是被据了;
“Reactor”公司 HR 就记下了你的联系方式,结果出来后会主动打电话通知你:有没有
被录取啊,还是被据了;你不用自己打电话去问结果,事实上也不能,你没有 HR 的留联系
方式。
2 Reactor 模式的优点
1)响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;
2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/
Reactor 模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:
进程的切换开销;
3)可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;
4)可复用性,reactor 框架本身与具体事件处理逻辑无关,具有很高的复用性;
3 Reactor 模式框架
使用 Reactor 模型,必备的几个组件:事件源、Reactor 框架、多路复用机制和事件处理
程序,先来看看 Reactor 模型的整体框架,接下来再对每个组件做逐一说明。
6
1) 事件源
Linux 上是文件描述符,Windows 上就是 Socket 或者 Handle 了,这里统一称为“句柄
集”;程序在指定的句柄上注册关心的事件,比如 I/O 事件。
2) event demultiplexer——事件多路分发机制
由操作系统提供的 I/O 多路复用机制,比如 select 和 epoll。
程序首先将其关心的句柄(事件源)及其事件注册到 event demultiplexer 上;
当有事件到达时,event demultiplexer 会发出通知“在已经注册的句柄集中,一个或多
Reactor,是事件管理的接口,内部使用 event demultiplexer 注册、注销事件;并运行事
个句柄的事件已经就绪”;
程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。
对应到 libevent 中,依然是 select、poll、epoll 等,但是 libevent 使用结构体 eventop 进行了
封装,以统一的接口来支持这些 I/O 多路复用机制,达到了对外隐藏底层系统机制的目的。
3) Reactor——反应器
件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。
对应到 libevent 中,就是 event_base 结构体。
一个典型的Reactor声明方式
class Reactor
{
public:
int register_handler(Event_Handler *pHandler, int event);
int remove_handler(Event_Handler *pHandler, int event);
void handle_events(timeval *ptv);
// ...
};
4) Event Handler——事件处理程序
事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供 Reactor 在相应的
事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。
对应到 libevent 中,就是 event 结构体。
下面是两种典型的 Event Handler 类声明方式,二者互有优缺点。
7
class Event_Handler
{
public:
virtual void handle_read() = 0;
virtual void handle_write() = 0;
virtual void handle_timeout() = 0;
virtual void handle_close() = 0;
virtual HANDLE get_handle() = 0;
// ...
};
class Event_Handler
{
public:
// events maybe read/write/timeout/close .etc
virtual void handle_events(int events) = 0;
virtual HANDLE get_handle() = 0;
// ...
};
4 Reactor 事件处理流程
前面说过 Reactor 将事件流“逆置”了,那么使用 Reactor 模式后,事件控制流是什么
样子呢?
可以参见下面的序列图。
8