Libevent源码学习(一) 支持多种网络模型原理

来源:互联网 发布:w7网络无internet访问 编辑:程序博客网 时间:2024/05/20 17:59

  在linux下学习了一段时间网络编程,主体的编程思路懂得差不多了(windows下做过,基本差不多),所以决定看些开源的库来实际学习一下.故选择了相对简练的libevent进行代码阅读.在读的过程中,参考了一位已经将libevent解析的很清楚的大神的博客.http://blog.csdn.net/sparkliang/article/details/4957667

这里算是自己学习过程中的一些结果写出来,供大家参考.源码使用的也是1.4.13稳定版.

一.支持多种网络模型原理

在libevent官网上,大家都看到libevent支持各种不同的网络模型,而且还支持跨平台.其实这部分如果从C++的编程思想来看,大家可以很容易想到,利用类的继承加上虚函数实现.

1.首先构建一个基类,定义接口函数

2.继承这个基类,实现多个不同网络模型方法(接口)

3.使用指向子类的基类指针实现统一访问

由于libevent使用纯C代码实现,所以上面的部分只是给大家回忆一下C++怎么实现的而已,但是基本思想差不多一致.下面结合libevent的实际代码说明.

1.基类与接口,本部分代码位于event-internal.h文件中

struct eventop {const char *name;void *(*init)(struct event_base *);int (*add)(void *, struct event *);int (*del)(void *, struct event *);int (*dispatch)(struct event_base *, void *, struct timeval *);void (*dealloc)(struct event_base *, void *);/* set if we need to reinitialize the event base */int need_reinit;};
eventop就是这个基类,这个也算是整个libevent工作过程中最实际干活的部分.eventop使用函数指针的方法去构建统一的接口,实现的接口包括初始化,添加事件,删除事件,分发事件,注销五个.事件的概念后续再说.

2.不同网络模型构建,本部分代码位于WIN32-Code/win32.c,devpoll.c,epoll.c,evport.c,kqueue.c,poll.c,select.c

本版本libevent支持7种不同网络模型,从上述文件即可看出.这里选用select.c进行解释,下面的代码位于select.c文件

static void *select_init(struct event_base *);static int select_add(void *, struct event *);static int select_del(void *, struct event *);static int select_dispatch(struct event_base *, void *, struct timeval *);static void select_dealloc     (struct event_base *, void *);const struct eventop selectops = {"select",select_init,select_add,select_del,select_dispatch,select_dealloc,0};
可以看出,首先第一步定义了5个select接口函数,并且构建了eventop实例selectops,注意这是个全局变量.同样大家可以从其他六个文件中找到相同的代码与全局变量定义.

下面的代码位于event.c文件中

#ifdef HAVE_EVENT_PORTSextern const struct eventop evportops;#endif#ifdef HAVE_SELECTextern const struct eventop selectops;#endif#ifdef HAVE_POLLextern const struct eventop pollops;#endif#ifdef HAVE_EPOLLextern const struct eventop epollops;#endif#ifdef HAVE_WORKING_KQUEUEextern const struct eventop kqops;#endif#ifdef HAVE_DEVPOLLextern const struct eventop devpollops;#endif#ifdef WIN32extern const struct eventop win32ops;#endif/* In order of preference */static const struct eventop *eventops[] = {#ifdef HAVE_EVENT_PORTS&evportops,#endif#ifdef HAVE_WORKING_KQUEUE&kqops,#endif#ifdef HAVE_EPOLL&epollops,#endif#ifdef HAVE_DEVPOLL&devpollops,#endif#ifdef HAVE_POLL&pollops,#endif#ifdef HAVE_SELECT&selectops,#endif#ifdef WIN32&win32ops,#endifNULL};
上面的代码使用预编译的方式来声明七种全局网络方法,具体使用那个网络方法就看编译环境了.

3.统一使用方法

这里用的时候就涉及到libevent的核心成员event_base了,event_base就类似于线程池模型中的管理模块一样.所有的事件都是由它管理的.先来看看event_base的结构定义.下面的代码位于event-internal.h中.

struct event_base {const struct eventop *evsel;void *evbase;int event_count;/* counts number of total events */int event_count_active;/* counts number of active events */int event_gotterm;/* Set to terminate loop */int event_break;/* Set to terminate loop immediately *//* active event management */struct event_list **activequeues;int nactivequeues;/* signal handling info */struct evsignal_info sig;struct event_list eventqueue;struct timeval event_tv;struct min_heap timeheap;struct timeval tv_cache;};
可以看得出来,event_base有eventop这个一个成员变量evsel,很明显,这个变量就是后续实际干活的实例了.

现在来看event_base是怎么初始化的,常用的是这么一个函数event_base_new().下面代码位于event.c文件中,已经删除无关部分

struct event_base *event_base_new(void){int i;struct event_base *base;if ((base = calloc(1, sizeof(struct event_base))) == NULL)event_err(1, "%s: calloc", __func__);/*删除部分代码*/base->evbase = NULL;for (i = 0; eventops[i] && !base->evbase; i++) {base->evsel = eventops[i];base->evbase = base->evsel->init(base);}/*删除部分代码*/return (base);}

这个event_base的evsel是使用咱们在第二步说到的全局变量赋值的,这样整个地方就很明了了.

要是还有些问题的话,再来看看event_base的核心函数event_base_loop,这是整个libevent事件的分发核心了.位于event.c文件中,已删除部分无关部分

intevent_base_loop(struct event_base *base, int flags){const struct eventop *evsel = base->evsel;void *evbase = base->evbase;struct timeval tv;struct timeval *tv_p;int res, done;/* clear time cache */base->tv_cache.tv_sec = 0;if (base->sig.ev_signal_added)evsignal_base = base;done = 0;while (!done) {/* Terminate the loop if we have been asked to *//* 删除部分代码 *//* clear time cache */base->tv_cache.tv_sec = 0;res = evsel->dispatch(base, evbase, tv_p);if (res == -1)return (-1);gettime(base, &base->tv_cache);/* 删除部分代码 */}/* clear time cache */base->tv_cache.tv_sec = 0;event_debug(("%s: asked to terminate loop.", __func__));return (0);}

从上面的整个过程中,已经很清晰的解释了libevent是怎么构建不同网络模型的.

剩下的部分咱们后续再说,重点还没说到....



0 0