写在前面:
libevent常规事件的总结使用步骤参考:libevent总结(一)-------libevent常规事件
正文:
一、bufferevent 原理:
bufferevent有两个缓冲区:读缓冲区和写缓冲区;分别对应原理如下: 读缓冲:读缓冲中如果有数据-> 会触发我们所写的读所对应的回调函数->回调函数调用 bufferevent_read() ->读数据。 (即bufferevent_read 替代了read函数) 写缓冲:写缓冲中如果有数据->会调用函数 bufferevent_write() ->写数据,发送给对端(即bufferevent_write代了 write函数)。若发送成功,会触发我们所写的写所对应的回调函数来通知我们发送完成了。
二:bufferevent 使用步骤:
第一步:创建event_base struct event_base * event_base_new(void);
第二步:创建 bufferevent 事件 struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options); 参数:base: event_base_new() 创建的对象 fd: 绑定到事件event的文件描述符 options: 一般是0,BEV_OPT_CLOSE_ON_FREE,释放底层的bufferevent。
返回:成功创建的bufferevent 事件对象;
第三步:给bufferevent事件对象设置回调
void bufferevent_setcb(struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg) 参数:bufev : bufferevent_socket_new()函数的返回值 readcb : 设置读缓对应的读回调 回调函数类型:typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);//ctx就是cbarg 我们定义的读缓冲的回调函数内部要调用bufferevent_read(),所以要看下这个函数原型: ev_size_t bufferevent_read(struct bufferevent *bufev, void *data, ev_size_t size); writecb: 设置写缓冲对应的回调 回调函数类型:typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);//ctx就是cbarg bufferevent_write()原型: int bufferevent_write(struct bufferevent *bufev, const void *data, ev_size_t size)
eventcb: 事件回调,一般用来设置错误回调 来看一下事件回调的类型:typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx); 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. */(请求的 连接过程已经完成,实现客户端时可用) cbarg : 上述回调函数的参数
第四步:缓冲区开启:
注意:新建的bufferevent写缓冲区是enable的,而读缓冲区是disable的,所以读的时候需要使能。
int bufferevent_enable(struct bufferevent *bufev, short event) 参数: bufev:bufferevent_socket_new()函数的返回值 event: #define EV_READ 0x02 //读使能 #define EV_WRITE 0x04 //写使能
第五步:缓冲区关闭:
int bufferevent_disable(struct bufferevent *bufev, short event); 参数跟bufferevent_enable()一致。
第六步:释放bufferevent void bufferevent_free(struct bufferevent *bufev); 参数:bufferevent_socket_new的返回值。
三:客户端和服务器连接和监听:
客户端: 一般的创建socket客户端步骤:socket(); connect();
int bufferevent_socket_connect(struct bufferevent *bev,struct hal_sockaddr *sa, int socklen);
参数:bev:即bufferevent_socket_new()函数的返回值。注意:fd已经封装在 bev对应的类型即bufferevent 里面了。 sa: 即服务器的IP地址结构; socklen: sa的长度;
服务器: 一般的创建socket服务器步骤: socket();bind();listen();accept();
bufferevent中的evconnlistener_new_bind()函数可替代 socket();bind();listen();accept();这四个函数。 evconnlistener_new_bind()函数原型: struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct hal_sockaddr *sa, int socklen); 参数: base:event_base_new()创建的base对象; cb : listen 回调函数 回调函数的类型:typedef void (*evconnlistener_cb)(struct evconnlistener *listener, evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr); 回调函数调用的时间:当接收到新连接时(即当有客户端连接时)会调用回调函数; 回调参数: listener:成功创建的监听器,即evconnlistener_new_bind返回值; sock: 新接收的套接字,即客户端的套接字; addr和len;分别是客户端的地址结构和长度; ptr:外部ptr传进来的参数。
ptr : 回调函数的参数 flags: LEV_OPT_CLOSE_ON_FREE:如果设置了这个选项,释放连接监听器会关闭底层套接字; LEV_OPT_REUSEABLE: 端口复用 backlog:int listen(SOCKET sockfd, int backlog);函数的第二个参数,-1,默认最大值; sa:服务器的IP+port; socklen: sa的长度
返回值:struct evconnlistener * ,成功创建的监听器。
释放创建成功的监听器对象:void evnlistener_free(struct evconnlistener *lev); |