设置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函数,并且设置了水位,有两种水位:低水位和高水位
函数原型如上,第一个参数由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);