libevent 是一个强大的跨平台的事件通知库,如果不想被多线程困扰,可以考虑这个平台,它从1.2.* 版本开始支持轻量级的http server 开发支持,随后陆续还推出轻量级 DNS server、RPC server 开发支持,网络上目前可参考的代码不多,希望可以给网友提供一些帮助

LIBEVENT的功能:

这组事件API提供了一种当某个指定文件描述符有效或时间到达时执行某个函数的机制.

在使用事件API前必须使用event_init()初始化.

In order to process events, an application needs to call

为了能够处理事件,应用程序必须调用event_dispatch(),该函数只当错误时返回,这时应该由用应程序接管事件.

函数event_set()

(原型

event_set(struct event *ev, int fd, short event,

void (*fn)(int, short, void *), void *arg);

)

用于生成事件结构体ev,以备event_add()event_del()使用.事件驱动程序将会调用void (*fn)(int, short, void *)中fn指定的函数,并传递三个参数int:文件描述符,short:事件类型,void*:其它参数由arg参数指定.

intfd指定要监视的文件描述符,

shortevent可以是EV_READ,EV_WRITEEV_READ|EV_WRITE表示该文件可以无阻塞地进行读写.

fn函数将会被调用,并传递给三个变量:

int fd:触发事件的文件描述符.

short event:触发事件的类型EV_TIMEOUT,EV_SIGNAL,EV_READ, orEV_WRITE.

void* :arg参数指定的变量.

另外重复注册的事件将会产生重复的事件通知.EV_PERSIST可以让注册的事件在执行完后不被删除,直到调用event_del()删除.

结构体初始化完成后,在无需改变内容的情况下,可以被event_add(),event_del()重复使用.但是当结构体被event_add()添加之后,必须保持结构体的内容,直到事件被执行后退出或调用event_del()删除该事件.不允许将这个结构体变量注册完事件后重复使用.每一个描述符都需要一个单独的event结构体变量.

event_add()函数使通过event_set()设置的事件在事件匹配或超时时(如果设置了超时)被执行.

event结构体变量必须先用event_set()初始化过,并且在事件被删除前不得再次调用event_set()来初始化之.如果事件发生超时,旧的超时时间会被新的超时时间所取代.

event_del()函数会取消event结构体所指定的事件,如果该事件已经执行或没有注册(在事件链表中不存在),该函数不会产生任何作用.

evtimer_set(),evtimer_add(),evtimer_del(),evtimer_initialized()evtimer_pending()函数()用于设置定时或超时操作.在这些函数中,文件描述符为-1,事件类型为EV_TIMEOUT.

signal_set(),signal_add(),signal_del(),signal_initialized(),signal_pending()等函数从略,其中事件类型为EV_SIGNAL.那就意味着signal_set()添加了EV_PERSIST.

为了避免信号竞争,事件API提供了两程变量:event_sigcb 和event_gotsig.某个信号的句柄设置event_gotsig表示收到信号.应用程序把event_sigcb设置成一个回调函数.当信号句柄设置了

event_gotsig之后,event_dispatch函数会执行回调函数处理接收到的信号.当没有事件注册时回调函数返回1.回调函数可以返回-1表示错误,这将导致event_dispatch()结束,错误代码为EINTR.

函数跟相似,但是它只调用回调函数一次,并且不需要调用者准备event结构体变量.该函数支持EV_TIMEOUT,EV_READ, andEV_WRITE.

event_pending()用于检测event结构体变量指定的事件是否处于等待状态.如果设定了EV_TIMEOUT,并且tv结构体指针变量非空,则事件终止时间由tv返回.

event_initialized()用于检测event结构体变量是否已经初始化.

event_loop提供一个接口用于单向执行等待事件.EVLOOP_ONCEEVLOOP_NONBLOCK有效.调用event_loopexit函数从事件循环中退出.在结定时间超时后下一个event_loop()重复将会正常完成然后不再等待事件直接退出.之后的event_loop()调用将会被正常执行.调用event_loopbreak函数直接从事件循环中退出.下一个事件完成后event_loop()会中止退出.event_loopbreak()典型的是被事件回调函数调用,这个特性类似于执行了break;语句.之后的event_loop()调用会正常进生

初始化event结构体变量中的回调函数是程序调用者必须提供的.


事件优先级

默认情况下,libevent以相同的优先级调度法动的事件.但是有时候希望以较其它事件更高的优先级处理某些事件.正因为如此,libevent支持精确的优先级队列.优先级值较低活动事件总是比优先级值较高的活动事件.

不同的优先级别可以使用event_priority_init()函数来初始化.该函数必须在之前调用.event_priority_set()函数用于设置事件的优先级.默认情况下libevent把所有事件的优先级设置成中间值,除非它们的优先级被明确指定.


线程安全事件

Libevent支持线程安全,当初始化事件库时调用event_init(),返回一个事件根基event base.这个事件根基可以被event_base_set(),event_base_dispatch(),event_base_loop(),event_base_loopexit(),bufferevent_base_set()andevent_base_free().等函数共同使用.

event_base_set()应该在event_set()初始化之后调用,因为函数event_set()对最近创建的事件根基赋值.在调用bufferevent_new()初始化缓存事件之后应该调用bufferevent_base_set().当不再需要事件根基时应该调用函数释放内存.


缓存事件

libevent 提供正常事件回调的一个抽象.这个抽象叫缓存事件.缓存事件提供输入输出缓存自动写入和读出.使用缓存事件的程序员不再需要直接处理IO,而是通过读写输入输出缓存.


bufferevent_new()使用创建新的缓存事件.

(原型:

struct bufferevent *

bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, everrorcb,

void *cbarg);

)

int fd:要读写数据的文件描述符.访文件描述符不允许是管道

接下来三个参数是回调:读写回调函数原型void (*cb)(struct bufferevent *bufev, void *arg)

错误处理回调函数原型:void (*cb)(struct bufferevent *bufev, shortwhat, void *arg)

其中arg参数由cbarg指定.读写回调函数可以是NULL,错误处理回调函数必须指定.

一旦初始化,缓存事件结构体可以被bufferevent_enable(),bufferevent_disable()重复使用.标志参数可以是EV_READEV_WRITE.当文件可读时缓存试图从文件描述符中读取数据然后调用回调函数.当缓存中的数据少于写的最低"水位线",写回调函数被调用.该最低"水位线"默认为0.

bufferevent_write()用于往文件中写入数据.该数据被自动释放到输出缓冲区,当文件可写时写入文件描述符.该函数成功返回0,失败返回-1.

bufferevent_read()用于读取输入缓冲区中的数据,返回读取的字节数.

如果使用多个事件根基,bufferevent_base_set()函数必须在延缓一次使能缓存事件时调用.


无阻塞HTTP支持

libevent支持所有轻量级的HTTP,可以且来作HTTP服务器也可以用来发HTTP请求.

HTTP服务器可以使用来创建calling evhttp_new().

也可以用evhttp_bind_socket()绑定所有端口和地址.HTTP服务器不再使用时,可以调用evhttp_free()释放.

要收到HTTP请求,用户应该注册一个HTTP服务器回调,可以用 evhttp_set_cb()来实现.该函数的第二个参数是回调函数注册的URI.相应的回调会收到一个evhttp_request的结构体对象,它包含请求的所有信息.

这里不有将所有函数调用一一介绍,请参考event.h查看API接口.

转自:http://lwg2001s.iteye.com/blog/289833