libevent(12)bufferevent的基础知识

一、bufferevent的基本概念

bufferevent 是 libevent 中的一个事件缓冲 IO,内部实现了基本 socket recv/send 操作 ,用户只需要调用 bufferevent 的 API 即可实现数据的读写。

(1)缓冲区:每个 bufferevent 都有一个读缓冲区(input)和写缓冲区(output),数据结构为 evbuffer ,它是一个数据缓冲区,用于缓存网络上发送或接收的数据。

(2)回调:

// 读取和写入回调
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);

// 事件回调,其中what表示发生的事件,具体后面有说明
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);

(3)水位:可以通过设置水位来调节回调函数的调用。

(3.1)读取低水位:输入缓冲区的数据量达到或超过此水位时,调用回调函数,即数据量达不到水位要求,则不会调用回调;

(3.2)读取高水位:输入缓冲区的数据量达到此水位时,bufferevent 将停止读取,直到输入缓冲区中的数据被读取,使得数据量低于此水位。注意用于限制一次读取的最大数据量。

(3.3)写入低水位:输出缓冲区中的数据量达到或低于此水位时,写入回调将被调用;

(3.4)写入高水位:不设置,直接写入即可,一般不用。

默认情况下,读取低水位和高水位都为 0,表示有数据就读取,且不会限定最大读取数量。写入的水位也是一样,表示可写即会全部写入。

 (4)事件回调函数中多了一个 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的基本接口

bufferevent 的接口都位于头文件 <event2/bufferevent.h> 中。

1、创建 bufferevent 上下文接口

struct bufferevent *bufferevent_socket_new(
	struct event_base *base, evutil_socket_t fd, int options);

参数说明:

(1)base :libevent 上下文;
(2)fd :socket 描述符,bufferevent 的读写操作都基于此描述符;
(3)options :可选项,定义如下:

enum bufferevent_options {
	// 释放bufferevent时,关闭底层socket传输
	BEV_OPT_CLOSE_ON_FREE = (1<<0),

	// 线程安全,即在bufferevent中使用lock,此时callback也会被加锁
	BEV_OPT_THREADSAFE = (1<<1),

	// 在事件循环中延迟回调
	BEV_OPT_DEFER_CALLBACKS = (1<<2),

	// 不对回调函数加锁,即便设置了BEV_OPT_THREADSAFE也不加锁
    // 此选项需要与BEV_OPT_DEFER_CALLBACKS一起使用,未来可能会移除这一要求
	BEV_OPT_UNLOCK_CALLBACKS = (1<<3)
};

一般使用 BEV_OPT_CLOSE_ON_FREE 选项,表示在 在 bufferevent_free 时也会关闭 socket 。

2、开启/关闭 bufferevent 操作

// 开启
int bufferevent_enable(struct bufferevent *bufev, short event);
// 关闭
int bufferevent_disable(struct bufferevent *bufev, short event);

event :指定使能事件,一般就是读写事件 EV_READ | EV_WRITE;

3、设置 bufferevent 的回调函数

void bufferevent_setcb(struct bufferevent *bufev,
    bufferevent_data_cb readcb, bufferevent_data_cb writecb,
    bufferevent_event_cb eventcb, void *cbarg);

包括 read、write、event 三个回调函数。

4、读取 bufferevent 缓冲区

size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); 

参数说明:

(1)data :存储数据的缓冲区;
(2)size :存储数据的缓冲区长度。

5、写入 bufferevent 缓冲区

int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size); 

返回值:成功返回 0,失败返回 -1。

6、设置 bufferevent 超时时间

int bufferevent_set_timeouts(struct bufferevent *bufev,
    const struct timeval *timeout_read, const struct timeval *timeout_write); 

参数说明:

(1)timeout_read :读超时,NULL 表示不超时;
(2)timeout_write :写超时,NULL 表示不超时。
返回值:成功返回 0,失败返回 -1。

可以使用如下方法判断是否为读写超时:

if ((what & BEV_EVENT_TIMEOUT) && (what & BEV_EVENT_READING)) { /* 读超时 */ }

if ((what & BEV_EVENT_TIMEOUT) && (what & BEV_EVENT_WRITING)) { /* 写超时 */ }

7、释放bufferevent

void bufferevent_free(struct bufferevent *bufev);

bufferevent_free 函数内部有引用计数,它会尽快的关闭,即在判断没有引用后才会闭关,不会立即关闭。如果设置了 BEV_OPT_CLOSE_ON_FREE 标志,在 bufferevent_free 时也会将 socket 关闭。

另外,需要注意,如果用 bufferevent_write 发送后立马调用 bufferevent_free 可能会导致部分数据没有发出去 ,所以不要过早关闭 bufferevent。

8、连接服务端 socket

一般用于客户端程序。

int bufferevent_socket_connect(struct bufferevent *bufev, 
	const struct sockaddr *addr, int socklen);

在调用此函数时,bufferevent 中的 socket fd 必须设置为 nonblock 。正常情况下,若连接成功,会引起 BEV_EVENT_CONNECTED 的事件回调。

猜你喜欢

转载自blog.csdn.net/mars21/article/details/131386362