赞
踩
设置buffevent_cb的函数原型
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
注意event_cb函数指针和readcb是不一样的,event_cb多了一个short参数,和之前学习的event事件的回调函数类似
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
read、write的函数指针类型
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
函数原型如下,在学习buffevent的时候我一直困惑,究竟是怎么记录客户端的套接字?通过断点调试终于解决了自己的疑惑,这个函数是这篇博客新增的介绍函数,在没有充分了解之前不随意去写这个函数,以免给人带来误会。
struct bufferevent *
bufferevent_socket_new(struct event_base *base,
evutil_socket_t fd,int options)
函数的实现如下,event_assign函数被调用,通过bufferevent成员变量event类型把客户端的套接字给绑定到了一起。下面给出了bufferevent的成员变量
struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_private *bufev_p; struct bufferevent *bufev; #ifdef _WIN32 if (base && event_base_get_iocp_(base)) return bufferevent_async_new_(base, fd, options); #endif if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) return NULL; if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket, options) < 0) { mm_free(bufev_p); return NULL; } bufev = &bufev_p->bev; evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); evbuffer_freeze(bufev->input, 0); evbuffer_freeze(bufev->output, 1); return bufev; }
bufferevent里面含有的成员变量
struct bufferevent { /** Event base for which this bufferevent was created. */ struct event_base *ev_base; /** Pointer to a table of function pointers to set up how this bufferevent behaves. */ const struct bufferevent_ops *be_ops; /** A read event that triggers when a timeout has happened or a socket is ready to read data. Only used by some subtypes of bufferevent. */ struct event ev_read; /** A write event that triggers when a timeout has happened or a socket is ready to write data. Only used by some subtypes of bufferevent. */ struct event ev_write; /** An input buffer. Only the bufferevent is allowed to add data to this buffer, though the user is allowed to drain it. */ struct evbuffer *input; /** An input buffer. Only the bufferevent is allowed to drain data from this buffer, though the user is allowed to add it. */ struct evbuffer *output; struct event_watermark wm_read; struct event_watermark wm_write; bufferevent_data_cb readcb; bufferevent_data_cb writecb; /* This should be called 'eventcb', but renaming it would break * backward compatibility */ bufferevent_event_cb errorcb; void *cbarg; struct timeval timeout_read; struct timeval timeout_write; /** Events that are currently enabled: currently EV_READ and EV_WRITE are supported. */ short enabled; };
个人理解,封装了recv和send函数,并且设置了水位,有两种水位:低水位和高水位
void bufferevent_setwatermark(struct bufferevent *bufev,
short events,size_t lowmark, size_t highmark);
函数原型如上,第一个参数由bufferevent_socket_new
创建,第二个是设置读还是写的水位,第三个是低水位的值、第四个高水位的值
0就是默认值,收到了就读了,当设置了低水位(下限)的值,收到了这么多的大小才会去处理,没有到达低水位的字节数的话就一直不处理。
0也是默认值,设置高水位(上界)超过这个值的话就要分批处理了
①先通过bufferevent_socket_new创建bufferevent的对象bev
②bufferevent_enable设置bev的属性(EV_READ 或者EV_WRITE),EV_READ设置可读事件、EV_WRITE设置可写事件。如果不设置EV_READ的话,客户端(telnet)发来的数据,服务器是不接受客户端的数据。这个函数一定要设置,默认是没有这两个属性的!
③bufferevent_setwatermark设置水位,如果低水位和高水位都不想设置的话可以不使用这个函数
④bufferevent_set_timeouts函数可以设置超时时间,第一个参数是bev,第二个参数是读超时时间,第三个是写超时时间
int bufferevent_set_timeouts(struct bufferevent *bufev,
const struct timeval *timeout_read, const struct timeval *timeout_write);
⑤bufferevent_setcb函数设置bev的回调函数们,第一个是bev,第二个是读的回调函数、第三个书写的回调函数,第四个是处理异常的回调函数,比如超时,第五个传任意一个参数
⑥具体代码看下面的完整代码
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
bufferevent* bev = bufferevent_socket_new(base,sock,BEV_OPT_CLOSE_ON_FREE); //把新连接的数据的操作添加到bufferevent中去 bufferevent_enable(bev,EV_READ | EV_WRITE); //设置低水位,最少多少数据才读 //高水位是超过这些数据就要控制接收的数据了 bufferevent_setwatermark(bev,EV_READ,5,//低水位 10//高水位就是0,相当于没有设置,默认就是0 ); /*没有测试出来写水位 //设置读取水位,字节数量低于低水位的话数据不会被发送 bufferevent_setwatermark(bev,EV_WRITE,20,//低水位 0//高水位就是0,相当于没有设置,默认就是0 ); */ //设置超时时间 timeval t1 = {3,0}; bufferevent_set_timeouts(bev,&t1,nullptr);//前面是读超时时间,后面是写超时时间 //设置回调函数,读的、写的、异常(超时等)回调函数 bufferevent_setcb(bev,read_cb,write_cb,event_cb,base);
#include <iostream> #include <event2/listener.h> #include <arpa/inet.h> #include <event2/event.h> #include <sys/types.h> #include <event2/bufferevent.h> #include <signal.h> #include <sys/socket.h> #include <string.h> using namespace std; //异常、超时、连接断开的情况下 void event_cb(bufferevent* bev,short events,void* arg){ cout<<"event_cb"<<endl; if(events & BEV_EVENT_TIMEOUT){ cout<<"time out "<<endl; //重新让他可读 //bufferevent_enable(bev,EV_READ); goto err; } else if(events & BEV_EVENT_ERROR){ goto err; } else { cout<<"others "<<endl; } err: bufferevent_free(bev); } //这里的写和读都是指的是服务器的读和写 void write_cb(bufferevent* bev,void* arg){ cout<<"有数据可写"<<endl; } void read_cb(bufferevent* bev,void* arg){ char data[1024] = { 0 }; int len = bufferevent_read(bev,data,sizeof(data)-1); if(len <= 0)return ; if(strstr(data,"quit") != nullptr){ cout<<"quit"<<endl; bufferevent_free(bev); return ; } cout<<"收到数据"<<data<<endl; //发送数据,echo服务器 bufferevent_write(bev,data,strlen(data)); } void listen_cb(evconnlistener* ev,int sock,sockaddr* sin, int sinlen,void* arg){ cout<<"listen_cb"<<endl; cout<<sock<<endl; event_base* base = static_cast<event_base*>(arg); //创建buffevent上下文 //BEV_OPT_CLOSE_ON_FREE清理buffevent清理socket //把sock也注册到了bufferevent中去了 bufferevent* bev = bufferevent_socket_new(base,sock,BEV_OPT_CLOSE_ON_FREE); //把新连接的数据的操作添加到bufferevent中去 bufferevent_enable(bev,EV_READ | EV_WRITE); //设置低水位,最少多少数据才读 //高水位是超过这些数据就要控制接收的数据了 bufferevent_setwatermark(bev,EV_READ,5,//低水位 10//高水位就是0,相当于没有设置,默认就是0 ); /*没有测试出来写水位 //设置读取水位,字节数量低于低水位的话数据不会被发送 bufferevent_setwatermark(bev,EV_WRITE,20,//低水位 0//高水位就是0,相当于没有设置,默认就是0 ); */ //设置超时时间 timeval t1 = {3,0}; bufferevent_set_timeouts(bev,&t1,nullptr);//前面是读超时时间,后面是写超时时间 //设置回调函数,读的、写的、异常(超时等)回调函数 bufferevent_setcb(bev,read_cb,write_cb,event_cb,base); } int main(int argc,char** argv){ int port = 9996; if(argc > 1){ port = atoi(argv[1]); } //忽略管道信号 if(signal(SIGPIPE,SIG_IGN) == SIG_ERR){ return 1; } //创建event的上下文 event_base* base = event_base_new(); if(base){ cout<<"event_base_new successful!"<<endl; } //创建网络服务器 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(9996); inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr); evconnlistener* ev =evconnlistener_new_bind(base,listen_cb,base, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, 10,(sockaddr*)&addr,sizeof(addr)); if(base) event_base_dispatch(base); if(ev){ evconnlistener_free(ev); } if(base) event_base_free(base); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。