libevent学习笔记

来源:互联网 发布:jsp页面连接数据库 编辑:程序博客网 时间:2024/05/22 13:04

先大概整理一下,再慢慢看

libevent:
事件驱动(event-driven),高性能;
轻量级,专注于网络,不如 ACE 那么臃肿庞大;
源代码相当精炼、易读;
跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;
支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;
支持 I/O,定时器和信号等事件;
注册事件优先级;

事件驱动设计模式——reactor模式:
应用程序需要提供相应的接口并注册到 Reactor 上,如果相应的时间发生, Reactor 将主动调用
应用程序注册的接口,这些接口又称为“回调函数”。

Reactor 模式的优点:
1)响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;
2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/
进程的切换开销;
3)可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;
4)可复用性, reactor 框架本身与具体事件处理逻辑无关,具有很高的复用性;

Reactor 模式框架
使用 Reactor 模型,必备的几个组件:事件源、 Reactor 框架、多路复用机制和事件处理程序
1) 事件源 Linux 上是文件描述符
2) event demultiplexer——事件多路分发机制 由操作系统提供的 I/O 多路复用机制,比如 select 和 epoll。
3) Reactor——反应器
Reactor,是事件管理的接口,内部使用 event demultiplexer 注册、注销事件;并运行事
件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。对应到 libevent 中,就是 event_base 结构体。
4) Event Handler——事件处理程序
事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供 Reactor 在相应的
事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。
对应到 libevent 中,就是 event 结构体。

使用 libevnet 的基本流程:
1)首先初始化 libevent 库,并保存返回的指针
struct event_base * base = event_init();实际上这一步相当于初始化一个 Reactor 实例;
在初始化 libevent 后,就可以注册事件了。

2)初始化事件 event,设置回调函数和关注的事件event_set 的函数原型是:   void event_set(struct event *ev, int fd, short event,                                            void (*cb)(int,short, void *), void *arg)ev:执行要初始化的 event 对象;fd:该 event 绑定的“句柄”,对于信号事件,它就是关注的信号;event:在该 fd 上关注的事件类型,它可以是 EV_READ, EV_WRITE, EV_SIGNAL;cb:这是一个函数指针,当 fd 上的事件 event 发生时,调用该函数执行处理,它有三个参数,调用时由 event_base 负责传入,按顺序,实际上就是 event_set 时的 fd, event 和 arg;arg:传递给 cb 函数指针的参数;3)设置 event 从属的 event_base  event_base_set(base, &ev);这一步相当于指明 event 要注册到哪个 event_base 实例上;4)是正式的添加事件的时候了event_add(&ev, timeout);    基本信息都已设置完成,只要简单的调用 event_add()函数即可完成,其中 timeout 是定时值;这一步相当于调用 Reactor::register_handler()函数注册事件。5)程序进入无限循环,等待就绪事件并执行事件处理   event_base_dispatch(base);实例代码:
struct event ev;    struct timeval tv;    void time_cb(int fd, short event, void *argc)    {    printf("timer wakeup\n");    event_add(&ev, &tv); // reschedule timer    }    int main()    {    struct event_base *base = event_init();    tv.tv_sec = 10; // 10s period    tv.tv_usec = 0;    evtimer_set(&ev, time_cb, NULL);    event_add(&ev, &tv);    event_base_dispatch(base);    }

事件处理流程:
1) 首先应用程序准备并初始化 event,设置好事件类型和回调函数;这对应于前面第步骤2 和 3;
2) 向 libevent 添加该事件 event。对于定时事件, libevent 使用一个小根堆管理, key 为超
时时间;对于 Signal 和 I/O 事件, libevent 将其放入到等待链表(wait list)中,这是一
个双向链表结构;
3) 程序调用 event_base_dispatch()系列函数进入无限循环,等待事件,以 select()函数为例;
每次循环前 libevent 会检查定时事件的最小超时时间 tv,根据 tv 设置 select()的最大等
待时间,以便于后面及时处理超时事件;
当 select()返回后,首先检查超时事件,然后检查 I/O 事件;
Libevent 将所有的就绪事件,放入到激活链表中;
然后对激活链表中的事件,调用事件的回调函数执行事件处理;

原创粉丝点击