libevent简介和使用
- 在官网下载http://libevent.org(libevent-2.0.22-stable.tar.gz)
tar -zxvf ibevent-2.0.22-stable.tar.gz - 解压后进入目录,进行配置,把库安装到/usr目录下
./configure --prefix=/usr - 编译安装
sudo makesudo make install
测试实例
简单定时器:实现程序每秒输出一个“Game Over!”
|
|
组成部分
- 事件管理包括各种IO(socket)、定时器、信号等事件,也是libevent应用最广的模块;
- 缓存管理是指evbuffer功能;
- DNS是libevent提供的一个异步DNS查询功能;
- HTTP是libevent的一个轻量级http实现,包括服务器和客户端
libevent使用
每个线程有且只有一个event_base,对应一个struct event_base结构体,用来schedule托管给它的一系列event。当一个事件发生后,event_base会在合适的时间去调用绑定在这个事件上的函数(传入一些预定义的参数,以及在绑定时指定的一个参数),直到这个函数执行完,再返回schedule其他事件。
创建一个event_base
|
|
event_base内部有一个循环,循环阻塞在epoll/kqueue等系统调用上,直到有一个/一些事件发生,然后去处理这些事件。当然,这些事件要被绑定在这个event_base上。每个事件对应一个struct event,可以是监听一个fd或者POSIX信号量之类。
创建并绑定一个event
struct event使用event_new来创建和绑定,使用event_add来启用:
|
|
libevent支持的事件及属性包括(使用bitfield实现,用 | 来让它们合体)
- EV_TIMEOUT: 超时
- EV_READ: 只要网络缓冲中还有数据,回调函数就会被触发
- EV_WRITE: 只要塞给网络缓冲的数据被写完,回调函数就会被触发
- EV_SIGNAL: POSIX信号量,参考manual吧
- EV_PERSIST: 不指定这个属性的话,回调函数被触发后事件会被删除
- EV_ET: Edge-Trigger边缘触发,参考EPOLL_ET
启动event_base的循环
循环的启动使用event_base_dispatch,循环将一直持续,直到不再有需要关注的事件,或者是遇到event_loopbreak()/event_loopexit()函数。
|
|
回调函数callback_func
typedef void(* event_callback_fn)(evutil_socket_t sockfd, short event_type, void *arg)
绑定到event的回调函数callback_func:传递给它的是一个socket fd、一个event类型及属性bit_field、以及传递给event_new的最后一个参数.
使用libevent创建服务器服务
基础流程
- listener = socket(),bind(),listen(),设置nonblocking
- 创建一个event_base
- 创建一个event,将该socket托管给event_base,指定要监听的事件类型,并绑定上相应的回调函数(及需要给它的参数)。对于listener socket来说,只需要监听EV_READ|EV_PERSIST
- 启用该事件
- 进入事件循环
- (异步) 当有client发起请求的时候,调用该回调函数,进行处理。
创建event处理read和write
- 将这个sockfd设置为nonblocking
- 创建2个event:
- event_read,绑上sockfd的EV_READ|EV_PERSIST,设置回调函数和参数
- event_write,绑上sockfd的EV_WRITE|EV_PERSIST,设置回调函数和参数
- 启用event_read事件
- (异步) 等待event_read事件的发生, 调用相应的回调函数。回调函数用recv读入的数据,不能直接用send丢给sockfd了事——因为sockfd是nonblocking的。所以需要一个自己管理的缓存用来保存读入的数据中(在accept以后就创建一个struct,作为第2步回调函数的arg传进来)。在合适的时间启用event_write事件[event_add(event_write, NULL)],等待EV_WRITE事件的触发
- (异步) 当event_write事件的回调函数被调用的时候,往sockfd写入数据,然后删除event_write事件[event_del(event_write)],等待event_read事件的下一次执行。
使用bufferevent改进服务
struct bufferevent内建了两个event(read/write)和对应的缓冲区[struct evbuffer input, output],并提供相应的函数用来操作缓冲区(或者直接操作bufferevent)。每当有数据被读入input的时候,read_cb函数被调用;每当output被输出完的时候,write_cb被调用;在网络IO操作出现错误的情况(连接中断、超时、其他错误),error_cb被调用。
- 设置sockfd为nonblocking
- 使用bufferevent_socket_new创建一个struct bufferevent *bev,关联该sockfd,托管给event_base.
- 使用bufferevent_setcb(bev, read_cb, write_cb, error_cb, (void *)arg)将EV_READ/EV_WRITE对应的函数.
- 使用bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST)来启用read/write事件
- (异步)处理函数
- 在read_cb里面从input读取数据,处理完毕后塞到output里(会被自动写入到sockfd)
- 在write_cb里面
- error_cb里面处理遇到的错误
|
|
可以从bev中用libevent的API提取出event_base、sockfd、input/output等相关数据
范例
|
|