libevent源码分析:bufferevent
struct bufferevent定义在文件bufferevent_struct.h中。
1 /** 2 Shared implementation of a bufferevent. 3 4 This type is exposed only because it was exposed in previous versions, 5 and some people's code may rely on manipulating it. Otherwise, you 6 should really not rely on the layout, size, or contents of this structure: 7 it is fairly volatile, and WILL change in future versions of the code. 8 **/ 9 struct bufferevent { 10 /** Event base for which this bufferevent was created. */ 11 struct event_base *ev_base; 12 /** Pointer to a table of function pointers to set up how this 13 bufferevent behaves. */ 14 const struct bufferevent_ops *be_ops; 15 16 /** A read event that triggers when a timeout has happened or a socket 17 is ready to read data. Only used by some subtypes of 18 bufferevent. */ 19 struct event ev_read; 20 /** A write event that triggers when a timeout has happened or a socket 21 is ready to write data. Only used by some subtypes of 22 bufferevent. */ 23 struct event ev_write; 24 25 /** An input buffer. Only the bufferevent is allowed to add data to 26 this buffer, though the user is allowed to drain it. */ 27 struct evbuffer *input; 28 29 /** An input buffer. Only the bufferevent is allowed to drain data 30 from this buffer, though the user is allowed to add it. */ 31 struct evbuffer *output; 32 33 struct event_watermark wm_read; 34 struct event_watermark wm_write; 35 36 bufferevent_data_cb readcb; 37 bufferevent_data_cb writecb; 38 /* This should be called 'eventcb', but renaming it would break 39 * backward compatibility */ 40 bufferevent_event_cb errorcb; 41 void *cbarg; 42 43 struct timeval timeout_read; 44 struct timeval timeout_write; 45 46 /** Events that are currently enabled: currently EV_READ and EV_WRITE 47 are supported. */ 48 short enabled; 49 };
libevent中的event结构对应套接字的某一个事件,读或者写,bufferevent结构对应一个套接字,其中有两个event结构:evread、evwrite。
对bufferevent的操作主要有:
1、bufferevent_socket_new,分配一个bufferevent对象并初始化,该函数内部依次调用了bufferevent_init_common_、event_assign(evread)、event_assign(evwrite),在该函数中只是初始化了读写事件,并没有调用event_add,两个事件的回调函数分别是定义在bufferevent_socket.c中的bufferevent_readcb、bufferevent_writecb,传递的参数是bufferevent指针。
2、bufferevent_new,分配一个bufferevent对象并设置回调,该函数的实现其实是依次调用了bufferevent_socket_new和bufferevent_setcb。
3、bufferevent_setcb,为bufferevent结构设置readcb、writecb、eventcb。
4、bufferevent_init_common_,初始化bufferevent公共的部分成员,例如:be_ops(设置bufferevent的行为)。
5、bufferevent_enable,使bufferevent生效(前面说过,初始化的时候并未调用event_add),该函数调用bufferevent的成员be_ops.enable,根据上面bufferevent_init_common_函数可知,enable实际调用了bufferevent_ops_socket.be_socket_enable,be_socket_enable调用了bufferevent_add_event_函数,bufferevent_add_event_函数调用了event_add。所以由此可以得知,使得evread、evwrite事件有效的函数是bufferevent_enable。
6、bufferevent_disable,使bufferevent失效,该函数调用关系类似于bufferevent_enable,bufferevent_disable->bufferevent.be_ops->bufferevent_ops_socket.be_socket_disable->event_del。
按照我对libevent的理解,evwrite在写完数据应该是被设置为无效的,因为正常情况下,一个套接字一直是可写的,所以写事件一直是有效的,所以需要找到bufferevent是怎么管理evread、evwrite事件的。
bufferevent的作用就是对数据的读写做一个缓存,所以调用bufferevent_setcb函数传入的readcb、writecb、eventcb三个回调函数,其中readcb应该是读取了一些数据之后被回调的,此时数据已经被读取到了evbuffer中;而writecb应该是写入了一些数据之后被回调的,此时应该应该已经将evwrite设置为无效的了,应该在调用完send之后执行的。bufferevent封装了底层的recv和send。
在调用bufferevent_socket_new中,调用了evbuffer_add_cb函数为output(对应输出的evbuffer)设置了相应的回调函数bufferevent_socket_outbuf_cb,在该函数中调用了bufferevent_add_event_,从上面的分析可以知道该函数会使evwrite事件生效,也就是开始监听可读事件,所以这里是使evwrite生效的地方。
在bufferevent_writecb中,可以找到当output中没有数据时,确实调用了bufferevent_disable,所以这里就是使evwrite失效的地方,由此跟我上面的推测一样。
到这里,关于bufferevent的分析就结束了。