bufferevent基础和概念
Libevent为这种带缓存的IO模式提供了一个通用的机制。一个”bufferevent”包含一个底层传输(比如socket),一个读buffer和一个写buffer。当底层传输可读写时就调用回调函数,这是普通事件的处理,而bufferevent是在读或写足够的数据时才调用用户指定的回调函数。
每个bufferevent都有一个输入缓存和一个输出缓存,对应的数据结构为struct evbuffer
。当你对一个bufferevent写数据,数据写入到输出缓存;当有数据可读时,你是从输入缓存中提取数据。
使用基于socket的bufferevent
基于socket的bufferevent使用起来最简单。基于socket的bufferevent使用Libevent的底层事件机制来检测底层网络socket是否可读写,也使用底层网络调用(比如readv,writev,WSASend,或者WSARecv)来传输和接收数据。
使用bufferevent_socket_new()
来创建。接口如下:
struct bufferevent *bufferevent_socket_new(
struct event_base *base,
evutil_socket_t fd,
enum bufferevent_options options);
base
是event_base,options
是bufferevent标志的位掩码(BEV_OPT_CLOSE_ON_FREE等)。而fd
则是可选的socket fd,如果你想稍后再设置fd,可以传-1。
bufferevent可选的标志
在创建一个bufferevent时你可以使用一个或多个标志。可用的标志有:
- BEV_OPT_CLOSE_ON_FREE
当bufferevent被释放时,关闭底层传输。这会关闭一个底层的socker,释放一个底层的bufferevent等。 - BEV_OPT_THREADSAFE
自动为bufferevent分配锁,所以可安全用于多线程。 - BEV_OPT_DEFER_CALLBACKS
如果设置了这个标志,bufferevent推迟所有回调的执行,如上所述。 - BEV_OPT_UNLOCK_CALLBACKS
默认上若一个bufferevent设置成线程安全,则当用户提供的回调调用时会获取该bufferevent的锁。设置这个标志来让Libevent在完成你的回调函数后释放bufferevent的锁。
提示: 确保你提供的socket是非阻塞模式的,Libevent提供了一个便捷的函数evutil_make_socket_nonblocking()
来设置一个socket为非阻塞。
如果成功,这个函数返回一个bufferevent,如果失败,返回NULL。
在bufferevent上启用连接
如果bufferevent的socket还没连接,你可以创建一个连接,接口:
int bufferevent_socket_connect(struct bufferevent *bev,
struct sockaddr *address, int addrlen);
参数address
和addrlen
跟标准的connect()
一样。如果bufferevent还没有一个socker,调用这个函数会为它创建一个新的socket,并设置socket为非阻塞。
如果bufferevent已经有一个socket,调用bufferevent_socket_connect()
告诉Libevent该socket未连接,在连接成功之前不会有读或写操作返回。
在连接返回前向输出buffer添加数据则是可以的。
如果连接成功建立,这个函数返回0,如果出现错误,返回-1。