bufferevent
特点介绍
带缓冲区的事件,借助队列实现的两个缓冲区,所以读过了就没了。
头文件 #include<event2/bufferevent.h>
一般用来跟socket搭配使用(上面的event配合fifo使用很少)
cfd在bufferlisten后返回,并且作为参数封装进bufferevent,后面使用的都是封装了cfd的函数(比如read跟write就没有cfd给他们传进行使用,所以封装了buffer自身的read和write)
- 结构体内带两个缓冲区,两个缓冲区能触发回调函数。同时,bufferevent不能使用普通的read和write函数,库封装了buffevent_read和bufferevent_write。两个缓冲区底层上还是在跟cfd交互。
read缓冲区的回调函数在缓冲区达到一定数量时候触发buffer_read回调函数
write缓冲区的回调函数在bufferevent_write写成功后才会调用。
bufferevent服务器端通信流程
流程中使用到的函数在后面有记录
- 创建base,
event_base_new()
- 创建服务器连接监听器,
evconnlistener_new_bind()
,监听到客户端连接时生成cfd,并且在回调函数中处理接受与客户端连接后的操作。 - 在监听器的回调中使用
bufferevent_socket_new()
创建一个新 bufferevent事件,将监听器返回的cfd封装到这个事件对象中 - 在监听器的回调中使用
bufferevent_setcb()
给这个事件对象的 read、write、event设置回调函数。(r、w的cb是缓冲区达到一定量时触发) - 在监听器的回调中设置 bufferevent的读写缓冲区 enable/disable(因为read缓冲区默认是disable)
- 在bufferevent_setcb中的读写回调中可以使用封装的读写函数
bufferevent_read()
/bufferevent_write()
读写缓冲区内容–>在bufferevent的读写回调中进行 - 启动循环监听
event_base_dispatch(base)
- 释放资源:监听器、base
bufferevent客户端通信流程
- 客户端不需要bind,也不需要监听器
- 直接connect到服务器端的IP端口地址结构体
- 客户端bufferevent不在回调函数内
函数
3个头文件汇总:
- 监听器
#include<event2/listener.h>
- bufferevent事件
#include<event2/bufferevent.h>
-
evconnlistener_new_bind()
**作用:**完成epoll中 socket(),bind(),listen(),accept()
四个函数的作用,创建lfd,绑定服务端ip端口地址结构,设置最大同时在线数,监听客户端连接请求返回cfd。
函数:
参数列表:
- 2是listener的回调函数,里面放着创建bufferevent事件之类的回调函数
- 3ptr是回调函数的参数,传base,从而给回调函数中的new做参数
- 4flags是设置LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,第一个设置关闭时自动释放底层套接字,第二个是设置端口复用
- 5backlog是listen()的参数2,设置最大同时在线数,-1表示最大值
- sa传入的服务器ip端口地址结构体,bind()的参数
- socklen服务器ip端口地址结构体的大小
- 返回值:成功创建的监听器
监听器的cp回调函数:
自动调用,参数分别是:之前返回监听器,cfd,客户端的地址结构体,长度,ptr是监听器的参数ptr,也就是传过来base。
bufferevent_socket_new()
创建bufferevent事件,在连接到客户端后创建,即在监听器的回调函数中创建struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, enum bufferevent_options options);
参数:
- 传入的是与客户端连接的套接字描述符 cfd,而不是用于监听的套接字描述符 lfd。
- BEV_OPT_CLOSE_ON_FREE ,option设置event释放的时候,自动关闭底层的套接字
- 返回值:创建号的事件对象(内含两个缓冲区)
buffevent_setcb()设置读写缓冲区回调函数
当缓冲区大小到一定程度就会触发readcb回调函数,而wirtecb回调函数是在写入完成后才触发(没什么用)。
前面event在新建事件的时候就设置好了回调: event_new( )参数中放入cb—>event_add()。
而bufferevent不同在setcb()函数中单独设置。
在listener的回调函数中直接调用语句就行。再内部的回调函数readcb之类的在全部定义即可。
void bufferevent_setcb(struct bufferevent * bufev,
bufferevent_data_cb readcb,
bufferevent_data_cb writecb,
bufferevent_event_cb eventcb,
void *cbarg );
参数:
- bufev 事件
- 读回调函数readcb(buffer_read一般在该回调函数触发时使用)
- 写回调函数writecb
- 可设置触发条件的回调函数,也可以传NULL
- 上述回调函数的参数
上面几种回调函数的设置:
read_cb:
write_cb(可以传NULL):int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);
eventcb:
参数3自己设置回调函数的函数原型
bufferevent缓冲区启动、关闭
读缓冲默认关闭,因此需要自己手动开启。