文章目录
bufferevent 基础概念
本章介绍 Libevent 中一个比较高级的概念 bufferevent 。
bufferevent 是 Libevent 中的一个事件缓冲 IO,内部实现了基本 socket recv/send 操作 ,用户只需要调用 bufferevent 的 API 即可实现数据的读写,而传统的 Libevent 使用方式则需要用户读写 socket,相对而言,bufferevent 更加方便。个人觉得,没有 asio 中的异步调用方便,可能是 C 语言实现的缘故吧,但也值得学习。
bufferevent 的结构体位于 <event2/bufferevent_struct.h>
文件中,定义如下:
struct bufferevent {
// 创建 bufferevent 的 event_base 对象
struct event_base *ev_base;
// 操作结构体,内部是一些函数指针,类似 struct eventop 结构体
const struct bufferevent_ops *be_ops;
// 读事件
struct event ev_read;
// 写事件
struct event ev_write;
// 读缓冲区,即输入缓冲区
struct evbuffer *input;
// 写缓冲区,即输出缓冲区
struct evbuffer *output;
// 读水位和写水位
struct event_watermark wm_read;
struct event_watermark wm_write;
// 数据可读回调函数
bufferevent_data_cb readcb;
// 数据可写回调函数
bufferevent_data_cb writecb;
// 发生错误的回调函数
bufferevent_event_cb errorcb;
// 回调参数,与上面3个回调函数配合使用
void *cbarg;
// 读写事件的超时时间,默认设为0
struct timeval timeout_read;
struct timeval timeout_write;
// 事件使能标志,目前只支持 EV_READ 和 EV_WRITE
short enabled;
};
bufferevent 的结构如下所示:
bufferevent 中的一些基础概念:
-
缓冲区:每个 bufferevent 都有一个读缓冲区(input)和写缓冲区(output),数据结构为 evbuffer ,它是一个数据缓冲区,用于缓存网络上发送或接收的数据。也是一个不透明的数据类型,即结构体的定义位于 Libevent 内部,只能通过 API 来操作,看不到具体定义,当然,用户也不必关心它的定义。
-
回调和水位:回调与基础的 event 类似,也分为读取回调、写入回调和事件回调,回调函数的定义如下:
// 读取和写入回调 typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx); // 事件回调,其中what表示发生的事件,具体后面有说明 typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
可以通过设置水位来调节回调函数的调用,水位
event_watermark
的定义比较简单,两个size_t
字段分别表示高低水位,又根据读写不同分为以下 4 类:- 读取低水位:输入缓冲区的数据量达到或超过此水位时,调用回调函数,即数据量达不到水位要求,则不会调用回调;
- 读取高水位:输入缓冲区的数据量达到此水位时,bufferevent 将停止读取,直到输入缓冲区中的数据被读取,使得数据量低于此水位。注意用于限制一次读取的最大数据量。
- 写入低水位:输出缓冲区中的数据量达到或低于此水位时,写入回调将被调用;
- 写入高水位:不设置,直接写入即可,一般不用。
默认情况下,读取低水位和高水位都为 0,表示有数据就读取,且不会限定最大读取数量。写入的水位也是一样,表示可写即会全部写入。
-
事件回调函数中多了一个 what 参数,表示发生的事件,目前支持的事件定义如下:
// 读取错误 #define BEV_EVENT_READING 0x01 /**< error encountered while reading */ // 写入错误 #define BEV_EVENT_WRITING 0x02 /**< error encountered while writing */ // 到达文件结尾 #define BEV_EVENT_EOF 0x10 /**< eof file reached */ // 不可恢复的错误 #define BEV_EVENT_ERROR 0x20 /**< unrecoverable error encountered */ // 到达直到的超时时间 #define BEV_EVENT_TIMEOUT 0x40 /**< user-specified timeout reached */ // 连接操作完成 #define BEV_EVENT_CONNECTED 0x80 /**< connect operation finished. */
最后,需要说明一点,目前 bufferevent 只支持 TCP 连接,未来可能支持 UDP 连接。