其实这些都是网络编程需要的库,这个库和libevent又是类似的东西,我们再分析一个,然后再做分析这个库和libevent之间的区别。主要的代码有ev.c event,c 然后再选择一个自己熟悉的I/O复用机制,这里估计还选择epoll吧!!!
libev是一个开源的事件驱动库,基于epoll,kqueue等OS提供的基础设施。其以高效出名,它可以将IO事件,定时器,和信号统一起来,统一放在事件处理这一套框架下处理。
libev的基本使用方法如下:
int main (void)
{
// use the default event loop unless you have special needs
struct ev_loop *loop = EV_DEFAULT;
// initialise an io watcher, then start it
// this one will watch for stdin to become readable
ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ);// 设置对stdin_watcher这个fd关注读事件,并指定回调函数
ev_io_start (loop, &stdin_watcher);// 激活stdin_watcher这个fd,将其设置到loop中
// initialise a timer watcher, then start it
// simple non-repeating 5.5 second timeout
ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.);//设置一个定时器,并指定一个回调函数,这个timer只执行一次,5.5s后执行
ev_timer_start (loop, &timeout_watcher);//激活这个定时器,将其设置到loop中
// now wait for events to arrive
ev_run (loop, 0);//循环开始
// break was called, so exit
return 0;
}
ibev中有一个抽象概念,叫做watcher(ev_watcher),libev中有各种各样的watcher,比如定时器watcher(struct ev_timer),I/O watcher(struct ev_io) , 信号watcher(struct ev_signal)
等等。这三个具体的watcher相当于父类watcher的子类。这种继承关系在C++这种高级语言中已内置,在C中实现就需要一些技巧,libev的作者使用了宏。
"父类"ev_watcher定义如下:
typedefstruct
ev_watcher
{<strong><span style="color: #ff0000;">EV_WATCHER(ev_watcher)</span></strong>
} ev_watcher;宏EV_WATCHER定义如下:
/* shared by all watchers */#define EV_WATCHER(type) \
intactive;
/* private */\
//该watcher是否被激活,加入到loop中
intpending;
/* private */\
//该watcher关注的events是否已触发
EV_DECL_PRIORITY/* private */
\ //int priority; 优先级,watcher是有优先级的
EV_COMMON/* rw */
\ // void *data;
EV_CB_DECLARE (type)/* private */
// void (*cb)(struct ev_loop *loop, type *w, int revents);回调函数
|
再看一个"父类"ev_watcher_list的定义:
typedefstruct
ev_watcher_list
{EV_WATCHER_LIST (ev_watcher_list)
} ev_watcher_list;
|
宏EV_WATCHER_LIST定义如下:
#define EV_WATCHER_LIST(type) \<strong><span style="color: #ff0000;"> EV_WATCHER (type)</span></strong> \
structev_watcher_list *next;
/* private */
|
可以看出,ev_watcher_list 其实也是ev_watcher的一个"子类", 它多了一个成员变量 struct ev_watcher_list *next;
这个成员变量用于将watcher串起来。
现在看一个I/O watcher 这个最重要的"子类":
typedefstruct
ev_io
{EV_WATCHER_LIST (ev_io)
intfd;
/* ro */// 显而易见,与io相关联的fd
intevents;
/* ro */// 这个watcher在fd上关注的事件
} ev_io; |
可以看出,ev_io是一种具体的watcher,它有两个自己专有的成员变量fd和events
下面看一下最关键的一个数据结构:
structev_loop
{ev_tstamp ev_rt_now;
#define ev_rt_now ((loop)->ev_rt_now)
// 这里decl是declare的意思,ev_vars.h 里面会定义一堆的变量,这些变量
// 都是本结构的成员,ev_vars.h展开的时候会用到下面这一行VAR的宏
#define VAR(name,decl) decl;
#include "ev_vars.h"
#undef VAR
}; |
ev_vars.h中包含很多关键的成员,比如:
epoll相关的成员变量:
#if EV_USE_EPOLL || EV_GENWRAPVARx(structepoll_event *, epoll_events)
// 相当于struct epoll_event *epoll_events
VARx(int, epoll_eventmax)//目前epoll_events数组的大小,可以扩充,每次以2倍的大小扩充
VARx(int, backend_fd)// 对于epoll来说,就是epoll使用的fd
//对于epoll来说,实际的函数是ev_epoll.c中的epoll_modify函数,这个函数会执行epoll_ctlVAR (backend_modify,void
(*backend_modify)(EV_P_int
fd, int
oev, intnev))<br>//对于epoll来说,实际的函数是ev_poll.c中的epoll_poll函数,这个函数会执行epoll_wait
VAR (backend_poll ,void
(*backend_poll)(EV_P_ ev_tstamp timeout))
|
与fd相关的成员变量:
VARx(ANFD *, anfds)//这个数组是以fd为索引
VARx(int, anfdmax)//上面数组的大小
VARx(int*, fdchanges)
// fdchangemax大小的数组,每个元素是一个fd,这个数组中存了所有epoll需要poll的fd
VARx(int, fdchangemax)//数组的容量
VARx(int, fdchangecnt)// 数组中实际的元素的大小
|
ANFD和fd一一对应,结构体ANFD如下:
typedefstruct
{WL head;// typedef ev_watcher_list *WL; 关注同一个fd的事件的watcher的链表,一个fd可以有多个watcher监听它的事件
unsignedchar
events; /* the events watched for */
// watcher链表中所有watcher关注的事件的按位与
unsignedchar
reify; /* flag set when this ANFD needs reification (EV_ANFD_REIFY, EV__IOFDSET) *///当这个结构体需要重新epoll_ctl则设置,说明关注的事件发生了变化
unsignedchar
emask; /* the epoll backend stores the actual kernel mask in here *///实际发生的事件
unsignedchar
unused;
#if EV_USE_EPOLLunsignedint
egen; /* generation counter to counter epoll bugs */
#endif#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCPSOCKET handle;
#endif#if EV_USE_IOCPOVERLAPPED or, ow;
#endif} ANFD; |
维护所有的"所关注的事件发生了的watcher",这些watcher的callback最后都需要被调用
VAR (pendings, ANPENDING *pendings [NUMPRI])//watcher是有优先级的,libev为每个优先级的watcher维护一个数组
VAR (pendingmax,
int pendingmax [NUMPRI])// 每个优先级watcher数组的容量
VAR (pendingcnt,
int pendingcnt [NUMPRI])// 每个优先级watcher数组实际大小
|
struct ANPENDING如下:
typedefstruct
{W w;//typedef ev_watcher *W;
intevents;
/* the pending event set for the given watcher *///events只指这个watcher关注了的并且已经发生了的还没有处理的事件
} ANPENDING; |
从示例程序可以看出,使用libev主要有几个方法:
ev_io_init
ev_io_start
ev_timer_init
ev_timer_start
ev_run
一个个看:
ev_io_init是个宏,主要就是设置ev_io中的各个成员
void ev_io_start(struct ev_loop *loop, ev_io *w) 会做如下几件事情:
1. 将参数w表示的watcher激活(w->active=1)
2. 将watcher w 加入到 w所关注的fd在anfds[](loop中)中相应的位置处的结构体ANFD中的watcher list链表中。
3. 将w所关注的fd加入到int *fdchanges数组中。
VARx(ANHE *, timers) |
struct ANHE定义如下:
/* a heap element */typedefstruct
{
ev_tstamp at;//timer watcher 到期时间
WT w;// typedef ev_watcher_time *WT;
} ANHE;typedefstruct
ev_watcher_time
{EV_WATCHER_TIME (ev_watcher_time)
} ev_watcher_time;#define EV_WATCHER_TIME(type) \EV_WATCHER (type) \
ev_tstamp at;/* private */
|
4. 调用backend_poll(loop, waittime)会做如下几件事:
对于使用epoll的系统来说,它实际上是调用ev_epoll.c 中的epoll_poll()函数,这个函数主要流程如下:
/* invoked when the given signal has been received */
/* revent EV_SIGNAL */typedefstruct
ev_signal
{EV_WATCHER_LIST (ev_signal)
intsignum;
/* ro *///信号id
} ev_signal;
ANSIG signals [EV_NSIG - 1];// 每个信号的信息用一个ANSIG结构体表示
typedefstruct
{EV_ATOMIC_T pending;
#if EV_MULTIPLICITYEV_P;
#endifWL head;//可以有多个watcher关注同一个信号,使用链表串起来
}ANSIG; |
VAR (evpipe,
int evpipe [2])// 用于将信号处理和事件处理框架结合在一起,evpipe[0]用于读,evpipe[1]用于写<br>VARx(ev_io, pipe_w) //这个I/O ev就是用于封装上面的pipe的读端,让epoll监听这个pipe_w,当接收到信号的时候,只需要在信号处理函数中往evpipe[1]中写即可
|
本文详细介绍了libev事件驱动库的使用方法,包括基本使用、watcher类的继承实现、关键数据结构以及如何将IO事件、定时器事件和信号统一到事件处理框架下。
910

被折叠的 条评论
为什么被折叠?



