前言
有了前面两节的铺垫,应该对Reactor模式和libevent中的基本流程有了一个基本的认识,接下来我们就可以分析源代码啦,不过在分析源代码之前,我们先来看一下源码结构。
絮叨
我在第一次把源代码下载下来的时候,一看代码,我有点懵,心想,libevent怎么这么随意,把代码文件都放在了一个文件下,也太乱了,然而并不是这样,仔细一研究,就发现,其实代码结构是非常清晰的。一起来看看吧:
代码结构
- 头文件:event.h:负则事件宏定义、声明接口函数、声明事件结构体event;
- 内部头文件:***-internal.h:内部的数据结构和函数,封装了供内部使用;
- event.c:event整体实现;
- 对I/O多路转接的封装 :epoll.c、select.c、devpoll.c、kqueue.c
- 定时器事件管理:min-heap.h:维护了一个小根堆管理时间
- 信号管理:signal.c:负则信号事件
- 辅助功能函数/工具函数:evuti.h evutil.c一些工具函数
- 日志:log.h log.c:负责打印日志信息
- 缓冲区:evbuffer.c buffer.c:负责管理缓冲区
- 数据结构:compat/sys下面的两个文件,封装了基本的数据结构链表队列等。
- 网络库:libevent实现了一个http服务器还有一个异步的dns查询库
小结:
这就是整个结构,其实是很清晰明了的
事件
事件是libevent的一个核心,看名字就知道了,的确libevent是由事件驱动的,整个工作都围绕着事件展开
struct event {
//事件对应的回调函数
struct event_callback ev_evcallback;
/* for managing timeouts */
//管理超时事件的,维护了一个小根堆,min_heap_idx小根堆中的索引,ev_next_with_common_timeout超时的指针
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;
int min_heap_idx;
} ev_timeout_pos;
//句柄,之前是int ev_fd;
evutil_socket_t ev_fd;
//这个就是事件关联的Reactor,后续会说的
struct event_base *ev_base;
union {
/* used for io events */
//对于I/O事件的指针和时间
struct {
LIST_ENTRY (event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
struct {
//维护信号事件的指针
LIST_ENTRY (event) ev_signal_next;
//回调函数的执行次数
short ev_ncalls;
/* Allows deletes in callback */
//指向上面变量的指针
short *ev_pncalls;
} ev_signal;
} ev_;
//事件类型有几种宏,后面再说
short ev_events;
//记录事件的激活类型
short ev_res; /* result passed to event callback */
//超时时间
struct timeval ev_timeout;
};
在c语言中,封装一些东西就是使用结构体,一层又一层,看起来十分复杂,好的封装,看起来又是井井有条,体现了设计者的智慧。
这一个版本比之前的封装了更多东西,大体还是没变的。
重点,libevent的事件管理:
从event结构体中,我们大致可以看出,其中有一个小根堆,一个激活事件的链表,一个注册I/O事件链表和一个信号事件链表。libevent的管理,其实就是不断地更新这些链表的状态,大体结构是这样,它的设计还有很多巧妙之处,我们后续再看。贴张图吧:
事件的接口函数
创建事件函数的原型:
struct event *event_new(struct event_base *base, evutil_socket_t fd,short what, event_callback_fn cb, void *arg);
使用这个函数可以获得一个事件对象:
base:就是Reactor,fd可以是文件描述符,或者socket等,也就是句柄,
what:是下面的集合,表示事件的类型
cb是回调函数,arg是参数
设置事件的优先级:当ev处于激活状态时不能设置,会返回-1
int event_priority_set(struct event *event, int priority);
注册事件:就是让事件被检测,后面会再说
int event_add(struct event *ev, const struct timeval *tv);
还有一些接口,后面会再继续说的。
总结
event是libevent的核心结构,整个libevent就是对各种事件的处理,切换事件的状态,然后去调用事件的回调函数,这就是libevent最核心的东西。
愿每一个程序员都能被温柔相待