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的分析就结束了。

原文地址:https://www.cnblogs.com/lit10050528/p/5858032.html