目录
- 参考
- bufferevent简单介绍
- 工作流程
- 事件
- Api
- 新建事件节点 bufferevent_socket_new
- 设置事件节点回调bufferevent_setcb
- 使事件势能bufferevent_enable
- 发送数据bufferevent_write
- 接收数据bufferevent_read
- evconnlistener的简介
参考
视频教程
libevent的基本使用
libevent–bufferevent的使用与实现
bufferevent简单介绍
一般通过libevent进行网络编程,都是将一个socket的fd与一个event进行绑定,并自行维护一个buffer用于存储从socket上接收的数据,同时可能也用于待发送数据的缓存。然后通过可读可写事件从socket上收取数据写入缓存并进行相应处理,或者将缓存中的数据通过socket发送。
libevent为这种带缓存的IO模式提供了一种通用的机制,那就是bufferevent。一个bufferevent包含了一个底层传输的fd(通常为socket),一个输入buffer和一个输出buffer,并且bufferevent已经帮我们完成了从socket上接收数据写入输入buffer,同时从输出buffer中取出数据通过socket发送,当输入输出缓存中的数据达到一定量时调用我们设置的回调函数。这样使得我们可以更加关注数据的处理。
event_base既可以监听event事件,也可以监听bufferevent事件
event:普通事件,文件描述符,事件(底层缓冲区的读事件或者写事件)触发 回调
bufferevent:高级event事件,bufferevent事件
工作流程
事件
- BEV_EVENT_READING
在读操作的时候,触发了一个事件。参考其他标识用来查看是哪个事件。 - BEV_EVENT_WRITING
在写的时候触发了事件,参考其他标识查看是哪个事件。 - BEV_EVENT_ERROR
在bufferevent操作时触发了错误。调用EVUTIL_SOCKET_ERROR()获取更多信息。 - BEV_EVENT_TIMEOUT
超时 - BEV_EVENT_EOF
触发了end-of-file标识 - BEV_EVENT_CONNECTED
完成了连接请求。
Api
新建事件节点 bufferevent_socket_new
struct bufferevent *bufferevent_socket_new(
struct event_base *base,
evutil_socket_t fd,
enum bufferevent_options options);
参数:
base:根节点
fd:要初始化上树的文件描述符
enum bufferevent_options options:
BEV_OPT_CLOSE_ON_FREE :释放 bufferevent 时关闭底层传输端口。这将关闭底层套接字,释放底层 bufferevent 等。
BEV_OPT_THREADSAFE :自动为 bufferevent 分配锁,这样就可以安全地在多个线程中使用 bufferevent。
BEV_OPT_DEFER_CALLBACKS :设置这个标志时, bufferevent 延迟所有回调,如上所述。
BEV_OPT_UNLOCK_CALLBACKS :默认情况下,如果设置 bufferevent 为线程安全 的,则 bufferevent 会在调用用户提供的回调时进行锁定。设置这个选项会让 libevent 在执行回调的时候不进行锁定。
返回值:
新建节点的地址
设置事件节点回调bufferevent_setcb
// 读写回调函数
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
// 事件回调函数
typedef void (*bufferevent_event_cb)(struct bufferevent *bev,short events, void *ctx);
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
参数:
bufev:新建节点的地址
readcb:读回调 从底层缓冲区拷贝到应用缓冲区
writecb:写回调
eventcb:异常回调
cbarg:传给回调函数的参数
void bufferevent_getcb(struct bufferevent *bufev,
bufferevent_data_cb *readcb_ptr,
bufferevent_data_cb *writecb_ptr,
bufferevent_event_cb *eventcb_ptr,
void **cbarg_ptr);
使事件势能bufferevent_enable
void bufferevent_enable(struct bufferevent *bufev, short events);
void bufferevent_disable(struct bufferevent *bufev, short events);
short bufferevent_get_enabled(struct bufferevent *bufev);
发送数据bufferevent_write
// 向bufferevent的输出缓冲区添加数据
int bufferevent_write(struct bufferevent *bufev,
const void *data, size_t size);
int bufferevent_write_buffer(struct bufferevent *bufev,
struct evbuffer *buf);
功能:这些函数向 bufferevent 的输出缓冲区添加数据。 bufferevent_write()将内存中从 data 处开 始的 size 字节数据添加到输出缓冲区的末尾 。bufferevent_write_buffer()移除 buf 的所有内 容,将其放置到输出缓冲区的末尾。成功时这些函数都返回 0,发生错误时则返回-1。
接收数据bufferevent_read
从bufferevent的输入缓冲区移除数据
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
int bufferevent_read_buffer(struct bufferevent *bufev,
struct evbuffer *buf);
这些函数从 bufferevent 的输入缓冲区移除数据。bufferevent_read()至多从输入缓冲区移除 size 字节的数据,将其存储到内存中 data 处。函数返回实际移除的字节数。 bufferevent_read_buffer()函数抽空输入缓冲区的所有内容,将其放置到 buf 中,成功时返 回0,失败时返回 -1。
注意,对于 bufferevent_read(),data 处的内存块必须有足够的空间容纳 size 字节数据。
evconnlistener的简介
参考:Libevent之evconnlistener详解
用户仅仅需要通过evconnlistener_new_bind传递回调函数,在aceept成功后,在回调函数里面处理已连接的套接字即可。省去了用户需要处理的一些列麻烦问题。
evconnlistener其实是对even_base和event的封装而已。
创建套接字 绑定 监听 提取
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,const struct sockaddr *sa, int socklen);
参数:
base: base根节点
cb: 提取cfd后调用的回调
ptr: 传给回调的参数
flags .
LEV_OPT_LEAVE SOCKETS BLOCKING 文件描述符为阻塞的
LEV_OPT_CLOSE ON FREE关闭时自动释放
LEV_OPT_REUSEABLE 端口复用
LEV_OPT_THREADSAFE 分配锁,线程安全
backlog: -1
sa:绑定地址信息
返回:
连接侦听器的地址
//一系列的工作函数,因为listener可以用于不同的协议。
struct evconnlistener_ops {
int (*enable)(struct evconnlistener *);
int (*disable)(struct evconnlistener *);
void (*destroy)(struct evconnlistener *);
void (*shutdown)(struct evconnlistener *);
evutil_socket_t (*getfd)(struct evconnlistener *);
struct event_base *(*getbase)(struct evconnlistener *);
};
//一层一层封装,加上隔离
struct evconnlistener {
const struct evconnlistener_ops *ops; //操作函数
void *lock; //锁变量,用于线程安全
evconnlistener_cb cb; //用户的回调函数
evconnlistener_errorcb errorcb; //发生错误时的回调函数
void *user_data; //回调函数的参数,当回调函数执行时候,通过形参传入回调函数内部
unsigned flags; //属性标志 ,例如socket套接字属性,可以是阻塞,非阻塞,reuse等。
short refcnt; //引用计数
unsigned enabled : 1; //位域为1.即只需一个比特位来存储这个成员
};
struct evconnlistener_event {
struct evconnlistener base;
struct event listener; //内部event,插入到event_base,完成监听
};