写在前面:
libevent常规事件的总结使用步骤参考:libevent总结(一)-------libevent常规事件
bufferevent 原理部分和函数分析部分参考:libevent总结(二)-------libevent bufferevent事件
正文:
一:bufferevent实现服务器流程:
(1):创建event_base;
(2):创建监听服务器:evconnlistener_new_bind();设置其回调函数,当有客户端成功连接时,这个回调函数会被调用;
(3):封装回调函数例如函数名叫listen_cb();在函数内部完成,完成与客户端通信;
(4):在listen_cb()回调中,创建创建 bufferevent 事件对象;
(5):使用bufferevent_setcb()函数给bufferevent的read、write、event设置回调函数;
(6):使能bufferevent的读写缓冲区;
(7):当监听的事件满足时,read_cb()会被调用,在其内部bufferev_read()读数据;
(8):启动循环监听:event_base_dispatch();
(9):释放连接;
注意:(4)、(5)、(6)、(7)步都是在监听器的回调函数中做的,因为server的bufferevent_socket_new()中的
fd参数是client的fd,在客户端连接成功后才可以进行数据的读写。
二:代码实现部分,注释部分已很详细
//读数据回调,要在读回调里面调用bufferevent_read()来完成对数据的读取
//然后调用bufferevent_write()函数将信息反馈给client
void read_cb(struct bufferevent *bev, void *ctx)
{
char buf[1024] = {0x0};
//读取client发过来的数据
int len = bufferevent_read(bev,buf, 1024);
printf("received %d byts,content is %s\n",len,buf);
//告诉client已成功接受数据
char *p = "Hi Client, Server received data succeed";
bufferevent_write(bev, p, strlen(p)+1); //注意这个函数执行成功后,我们设置的写回调将会被调用哦
sleep(3);
}
//写回调,当bufferevent_write发送成功后,这里会被调用
void write_cb(struct bufferevent *bev, void *ctx)
{
printf("datas tx succeed\n");
}
//事件回调
void event_cb(struct bufferevent *bev, short what, void *ctx)
{
if(what & BEV_EVENT_READING )
{
printf("BEV_EVENT_READING event happend\n");
//次错误发送要释放 bufferevent资源
bufferevent_free(bev);
}
if(what & BEV_EVENT_WRITING )
{
printf("BEV_EVENT_WRITING event happend\n");
//次错误发送要释放 bufferevent资源
bufferevent_free(bev); }
if(what & BEV_EVENT_EOF )
{
printf("BEV_EVENT_EOF event happend\n");
//次错误发送要释放 bufferevent资源
bufferevent_free(bev); }
if(what & BEV_EVENT_ERROR )
{
printf("BEV_EVENT_ERROR event happend\n");
//次错误发送要释放 bufferevent资源
bufferevent_free(bev); }
if(what & BEV_EVENT_TIMEOUT )
{
printf("BEV_EVENT_TIMEOUT event happend\n");
//次错误发送要释放 bufferevent资源
bufferevent_free(bev); }
if(what & BEV_EVENT_CONNECTED )
{
printf("BEV_EVENT_CONNECTED event happend\n");
}
}
//监听回调函数,注意,有回调来说明,客户端已经与服务器连接
//另外,回调中的sock和 addr都是客户端的信息
void listener_cb(struct evconnlistener *listener,evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr)
{
printf("client connect server succeess\n");
//基于传进来的 event_base来创建bufferevent对象
event_base * base = (event_base * )ptr;
struct bufferevent * bev = bufferevent_socket_new(base, sock,BEV_OPT_CLOSE_ON_FREE);
//给bufferevent事件对象设置回调
bufferevent_setcb(bev,read_cb, write_cb, event_cb, NULL);
//使能读写缓冲区
bufferevent_enable(bev, EV_READ|EV_WRITE);
}
int main(void)
{
//创建 event_base
struct event_base * even_base = event_base_new();
//设置服务器的地址和IP
struct sockaddr_in serv;
memset(serv,0,sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = honts(5678);
serv.sin_addr.s_addr = hontl(INADDR_ANY);
// 创建监听服务器
struct evconnlistener * listener = NULL;
//注意这里第三个参数为even_base的目的是当连接成功后,将这个参数传递给回调,
//回调中基于这个event_base来创建bufferevent 对象结构体
listener = evconnlistener_new_bind(even_base,listener_cb, even_base, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
&serv, sizeof(serv));
//启动循环监听
event_base_dispatch(even_base);
//释放资源
evconnlistener_free(listener);
event_base_free(even_base);
return 0;
}