libevent简介:Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。
libevent的使用:在下载安装好了后,包含相应的头文件就可以使用封装好了的一些函数
常用头文件:#include
#include
编译使用到libevent相应函数的时候需要在编译命令后加入 -levent
1.事件处理框架 - event_base
使用 libevent 函数之前需要分配一个或者多个 event_base 结构
体。 每个event_base 结构体持有一个事件集合,可以检测以确定哪
个事件是激活的。
相当于epoll红黑数的树根,位于抽象层,完成对event_base的封装,每个event_base都有一种用于检测哪种事件已经就绪的方法或者说后端
2.event_base的相应操作
创建
struct event_base* event_base_new(void);
释放
event_base_free(struct event_base*base);
循环监听
event_base_dispatch();
查看event_base封装的后端
const char event_get_supported_methods(void);
char *str[];
const char * event_base_get_method(const struct event_base *base);
libevent的使用流程
1.创建事件处理框架
2.创建事件
3.事件添加到事件处理框架上
4.开始事件循环
5.释放资源
事件循环-event_loop
一旦有了一个已经注册了某些事件的 event_base, 就需要让libevent 等待事件并且通知事件的发生。
#define EVLOOP_ONCE 0x01
事件只会被触发一次
事件没有被触发, 阻塞等
#define EVLOOP_NONBLOCK 0x02
非阻塞 等方式去做事件检测
不关心事件是否被触发了
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
没有事件的时候, 也不退出轮询检测
1 .int event_base_loop(struct event_base base, int flags);
a. 正常退出返回0, 失败返回-1
2. int event_base_dispatch(struct event_base base);
等同于没有设置标志的 event_base_loop ( )
将一直运行,直到没有已经注册的事件了,或者调用 了
event_base_loopbreak()或者 event_base_loopexit()为止
事件创建 - event
typedef void (*event_callback_fn)(evutil_socket_t, short, void *); struct event *event_new(
struct event_base *base,
evutil_socket_t fd, - // 文件描述符 - int short what,
event_callback_fn cb, // 事件的处理动作 void *arg
);
○调用event_new()函数之后, 新事件处于已初始化和非未决状态
2.释放事件
void event_free(struct event *event);
3.设置未决事件
构造事件之后,在将其添加到 event_base 之前实际上是不能对其做任何操作的。使用event_add()将事件添加到event_base, 非未决事件 -> 未决事件.
○int event_add(
struct event *ev,
const struct timeval *tv
);
-tv:
NULL: 事件被触发, 对应的回调被调用
tv = {0, 100}, 如果设置的时间,
在改时间段内检测的事件没被触发, 时间到达之后, 回调函数还是会被调用
函数调用成功返回0, 失败返回-1
4.设置非未决
○int event_del(struct event *ev);
对已经初始化的事件调用 event_del()将使其成为非未决和非激活的。如果事件不是
未决的或者激活的,调用将没有效果。成功时函数返回 0,失败时返回-1。
数据缓冲区 - Bufferevent
1.event2/bufferevent.h
2.bufferevent 理解:
是libevent为IO缓冲区操作提供的一种通用机制
bufferevent 由一个底层的传输端口(如套接字 ), 一个读取缓冲区和一个写入缓冲区组成。
与通常的事件在底层传输端口已经就绪,可以读取或者写入的时候执行回调不同的是, bufferevent 在读取或者写入了足够量的数据之后调用用户提供的回调。
3.回调 - 缓冲区对应的操作
○每个 bufferevent 有两个数据相关的回调
一个读取回调
□从底层传输端口读取了任意量的数据之后 读缓冲区对应的回调会被调用
会调用读取回调(默认)
一个写入回调
输出缓冲区中足够量的数据被清空到底层
传输端口后写入回调会被调用(默认)bufferevent_read();bufferevent_write();
使用 bufferevent
1.创建基于套接字的bufferevent
○可以使用 bufferevent_socket_new()创建基于套接
字的 bufferevent
struct bufferevent *bufferevent_socket_new( struct event_base *base, evutil_socket_t fd,
enum bufferevent_options options
);
options: BEV_OPT_CLOSE_ON_FREE
□释放 bufferevent 时关闭底层传输端口。这将关闭底层套接字,释放底层 bufferevent 等
□参考手册page53 - bufferevent的选项标志
struct bufferevent也是一个 event
成功时函数返回一个 bufferevent,失败则返回NULL。
2.在bufferevent上启动链接
○int bufferevent_socket_connect(
struct bufferevent *bev,
struct sockaddr *address, - server ip和port
int addrlen
);
address 和 addrlen 参数跟标准调用 connect() 的参数相同。如果还没有为bufferevent 设置套接字,调用函数将为其分配一个新的流套接字,并且设置为非阻塞的
如果已经为 bufferevent 设置套接字,调用 bufferevent_socket_connect() 将告知libevent套接字还未连接,直到连接成功之前不应该对其进行读取或者写入操作。连接完成之前可以向输出缓冲区添加数据
3.释放bufferevent操作
○void bufferevent_free(struct bufferevent *bev);
这个函数释放 bufferevent
4.bufferevent读写缓冲区回调操作
typedef void (*bufferevent_data_cb)(
struct bufferevent *bev,
void *ctx
);
typedef void (*bufferevent_event_cb)(
struct bufferevent *bev,
short events,
void *ctx
);
events参数:
EV_EVENT_READING:读取操作时发生某事件,具体是哪种事件请看其他标志。
BEV_EVENT_WRITING:写入操作时发生某事件,具体是哪种事件请看其他标志。
BEV_EVENT_ERROR:操作时发生错误。关于错误的更多信息,请调 用
EVUTIL_SOCKET_ERROR()。
BEV_EVENT_TIMEOUT:发生超时。
BEV_EVENT_EOF:遇到文件结束指示。
BEV_EVENT_CONNECTED:请求的连接过程已经完成
实现客户端的时候可以判断
void bufferevent_setcb(
struct bufferevent *bufev,
bufferevent_data_cb readcb,
–在读回调中读数据
–bufferevent_read() bufferevent_data_cb writecb,
–NULL
bufferevent_event_cb eventcb,
NULL
5.禁用、启用缓冲区
○禁用之后, 对应的回调就不会被调用了
void bufferevent_enable(
struct bufferevent *bufev,
short events
);
void bufferevent_disable(
struct bufferevent *bufev,
short events
);
short bufferevent_get_enabled(
struct bufferevent *bufev
);
可以启用或者禁用 bufferevent 上的 EV_READ、EV_WRITE或者 EV_READ | EV_WRITE 事件。没有启用读取或者写入事件时, bufferevent 将不会试图进行数据读取或者写入。
6.操作bufferevent中的数据
○向bufferevent的输出缓冲区添加数据
int bufferevent_write(
struct bufferevent *bufev,
const void *data,
size_t size
);
○从bufferevent的输入缓冲区移除数据
size_t bufferevent_read( struct bufferevent *bufev, void *data,
size_t size);
链接监听器 - evconnlistener
1.创建和释放evconnlistener
typedef void (*evconnlistener_cb)( struct evconnlistener *listener,
evutil_socket_t sock,
◊用于通信的文件描述符
struct sockaddr *addr,
◊客户端的IP和端口信息
int len,
void *ptr
);
○struct evconnlistener * evconnlistener_new( struct event_base *base, evconnlistener_cb cb,
void *ptr, unsigned flags, int backlog,
evutil_socket_t fd);
○struct evconnlistener *evconnlistener_new_bind( struct event_base *base,
evconnlistener_cb cb, — 接受连接之后, 用户要做的操作 void *ptr, // 给回调传参
unsigned flags, int backlog,
----1: 使用默认的最大值 const struct sockaddr *sa,
---- 服务器的IP和端口信息 int socklen);
两个 evconnlistener_new*()函数都分配和返回一个新的连接监听器对象。连接监听器使 用 event_base
2.启用和禁用 evconnlistener
○int evconnlistener_disable(struct evconnlistener *lev);
○int evconnlistener_enable(struct evconnlistener *lev);
这两个函数暂时禁止或者重新允许监听新连接。
3.调整 evconnlistener 的回调函数
void evconnlistener_set_cb(
struct evconnlistener *lev,
evconnlistener_cb cb,
void *arg
重要函数总结
必须要掌握的函数:
-创建event_base
○struct event_base* event_base_new(void);
○失败返回NULL
-释放event_base
○event_base_free(struct event_base* base);
-事件创建 - 没有缓冲区
○struct event *event_new()
○int event_add(
struct event *ev,
const struct timeval *tv
);
○释放事件
void event_free(struct event *event);
-开始事件循环
○int event_base_dispatch(struct event_base* base);
套接字通信
1.创建带缓冲区的事件
struct bufferevent *bufferevent_socket_new( struct event_base *base, evutil_socket_t fd,
enum bufferevent_options options
);
○给读写缓冲区设置回调
void bufferevent_setcb(
struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg
);
void bufferevent_enable(
struct bufferevent *bufev,
short events
);
2.套接字通信, 客户端连接服务器
○int bufferevent_socket_connect( struct bufferevent *bev,
struct sockaddr *address, - server ip和port int addrlen
);
3.服务器端用的函数
○创建监听的套接字
○绑定
○监听
○接收连接请求
○struct evconnlistener *evconnlistener_new_bind( struct event_base *base, evconnlistener_cb cb,
void *ptr, unsigned flags, int backlog,
const struct sockaddr *sa, int socklen);
操作bufferevent中的数据
○向bufferevent的输出缓冲区添加数据
int bufferevent_write(
struct bufferevent *bufev,
const void *data,
size_t size
);
○从bufferevent的输入缓冲区移除数据
size_t bufferevent_read( struct bufferevent *bufev, void *data,
size_t size
);