最近几天一直在看libevent的源代码。
看的方法是:
①网络上一些大牛的博客资料
②libevent源代码(版本:Libevent 2.0.16-stable)
③libevent例子程序
④libevent相关文档
特别推荐的学习资料是张亮大牛的Blog:http://blog.csdn.net/sparkliang/article/category/660506
跟着这个资料,再动手调一下库中自带的例子程序,你很容易就能够了解libevent的事件处理流程。
下面是一个对例子程序hello-world.c写的一个client程序:
1 /* Don't actually copy this code: it is a poor way to implement an
2 HTTP client. Have a look at evhttp instead.
3 */
4 #include <event2/bufferevent.h>
5 #include <event2/buffer.h>
6 #include <event2/event.h>
7 #include <sys/socket.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 void readcb(struct bufferevent *bev, void *ptr)
12 {
13 char buf[1024];
14 int n;
15 struct evbuffer *input = bufferevent_get_input(bev);
16 while ((n = evbuffer_remove(input, buf, sizeof(buf))) > 0)
17 {
18 fwrite(buf, 1, n, stdout);
19 }
20 }
21
22 void eventcb(struct bufferevent *bev, short events, void *ptr)
23 {
24 if (events & BEV_EVENT_CONNECTED)
25 {
26 printf("Connect okay.\n");
27 }
28 else if (events & (BEV_EVENT_ERROR|BEV_EVENT_EOF))
29 {
30 struct event_base *base = (struct event_base *)ptr;
31 if (events & BEV_EVENT_ERROR)
32 {
33 printf("BEV_EVENT_ERROR\n");
34 }
35 printf("Closing\n");
36 bufferevent_free(bev);
37 event_base_loopexit(base, NULL);
38 }
39 }
40
41 int main(int argc, char **argv)
42 {
43 struct event_base *base;
44 struct bufferevent *bev;
45 struct sockaddr_in sin;
46
47 base = event_base_new();
48
49 memset(&sin, 0, sizeof(sin));
50 sin.sin_family = AF_INET;
51 sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
52 sin.sin_port = htons(9995);
53
54 bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
55 //set callback function
56 bufferevent_setcb(bev, readcb, NULL, eventcb, base);
57 //enable read event
58 bufferevent_enable(bev, EV_READ);
59 //disabel write event
60 bufferevent_disable(bev, EV_WRITE);
61
62 if (bufferevent_socket_connect(bev,(struct sockaddr *)&sin, sizeof(sin)) < 0)
63 {
64 bufferevent_free(bev);
65 return -1;
66 }
67
68 event_base_dispatch(base);
69
70 return 0;
71 }
通过这个例子可以知道,libevent在处理事件的大体过程是:
①通过event_base_new()创建一个event_base实例
②通过event_add()(这里使用的是bufferevent_socket_new())将一个event绑定到一个base
③设置相应的I/O事件回调函数(读写事件),信号事件回调函数,超时事件回调函数等参数
④调用event_base_dispatch()进入事件主循环,其间触发什么事件,就调用相应的事件回调函数进行处理
其他:
①libevent用到的基本数据结构主要是双向链表和最小堆,用双向链表存储事件,用最小堆处理超时
②libevent根据系统选择处理异步IO的方法,可以通过相关API查询系统支持的方法,例如:
1 #include <event2/event.h>
2 #include <stdio.h>
3
4 int main(int argc, char *argv[])
5 {
6 int i;
7 const char **methods = event_get_supported_methods();
8 printf("Starting Libevent %s. Available methods are:\n", event_get_version());
9
10 for (i=0; methods[i] != NULL; ++i)
11 {
12 printf(" %s\n", methods[i]);
13 }
14
15 struct event_base *base;
16 enum event_method_feature f;
17
18 base = event_base_new();
19 if (!base)
20 {
21 puts("Couldn't get an event_base!\n");
22 }
23 else
24 {
25 printf("Using Libevent with backend method %s.", event_base_get_method(base));
26 f = (enum event_method_feature)event_base_get_features(base);
27 if ((f & EV_FEATURE_ET))
28 printf(" Edge-triggered events are supported.\n");
29 if ((f & EV_FEATURE_O1))
30 printf(" O(1) event notification is supported.\n");
31 if ((f & EV_FEATURE_FDS))
32 printf(" All FD types are supported.\n");
33 puts("");
34 }
35
36 event_base_free(base);
37
38 return 0;
39 }
参考资料:
1、张亮《libevent源码深度剖析系列》:http://blog.csdn.net/sparkliang/article/category/660506
2、libevent官方文档:http://www.wangafu.net/~nickm/libevent-book/
3、《libevent源码浅析:事件处理框架》:
http://godorz.info/2011/02/the-annotated-libevent-sources-about-event-handling-framework/
4、《libevent源码分析:min_heap带来的超时机制》:http://www.cppblog.com/kevinlynx/archive/2008/07/18/56511.html