LIBEVENT事件驱动库(跨平台)介绍
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参数指定.
int fd 指定要监视的文件描述符,
short event 可以是EV_READ,EV_WRITE或EV_READ|EV_WRITE表示该文件可以无阻塞地进行读写.
fn函数将会被调用,并传递给三个变量:
int fd:触发事件的文件描述符.
short event:触发事件的类型EV_TIMEOUT,EV_SIGNAL, EV_READ, or EV_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, and EV_WRITE.
event_pending()用于检测event结构体变量指定的事件是否处于等待状态.如果设定了EV_TIMEOUT,并且tv结构体指针变量非空,则事件终止时间由tv返回.
event_initialized()用于检测event结构体变量是否已经初始化.
event_loop提供一个接口用于单向执行等待事件.EVLOOP_ONCE和 EVLOOP_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() and event_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, short what, void *arg)
其中arg参数由cbarg指定.读写回调函数可以是NULL,错误处理回调函数必须指定.
一旦初始化,缓存事件结构体可以被bufferevent_enable(),bufferevent_disable()重复使用.标志参数可以是EV_READ 和EV_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接口.
该文档不是不完整也不是权威著作.如果你对API操作有异意,请查看源码如何工作.
所有操作成功返回0,错误返回-1,错误代码在errno中.
LIBEVENT 函数
struct event_base *
event_init(void);
int
event_dispatch(void);
int
event_loop(int flags);
int
event_loopexit(struct timeval *tv);
int
event_loopbreak(void);
void
event_set(struct event *ev, int fd, short event,
void (*fn)(int, short, void *), void *arg);
int
event_base_dispatch(struct event_base *base);
int
event_base_loop(struct event_base *base, int flags);
int
event_base_loopexit(struct event_base *base, struct timeval *tv);
int
event_base_loopbreak(struct event_base *base);
int
event_base_set(struct event_base *base, struct event *);
void
event_base_free(struct event_base *base);
int
event_add(struct event *ev, struct timeval *tv);
int
event_del(struct event *ev);
int
event_once(int fd, short event, void (*fn)(int, short, void *),
void *arg, struct timeval *tv);
int
event_base_once(struct event_base *base, int fd, short event,
void (*fn)(int, short, void *), void *arg, struct timeval *tv);
int
event_pending(struct event *ev, short event, struct timeval *tv);
int
event_initialized(struct event *ev);
int
event_priority_init(int npriorities);
int
event_priority_set(struct event *ev, int priority);
void
evtimer_set(struct event *ev, void (*fn)(int, short, void *), void *arg);
void
evtimer_add(struct event *ev, struct timeval *);
void
evtimer_del(struct event *ev);
int
evtimer_pending(struct event *ev, struct timeval *tv);
int
evtimer_initialized(struct event *ev);
void
signal_set(struct event *ev, int signal, void (*fn)(int, short, void *),
void *arg);
void
signal_add(struct event *ev, struct timeval *);
void
signal_del(struct event *ev);
int
signal_pending(struct event *ev, struct timeval *tv);
int
signal_initialized(struct event *ev);
struct bufferevent *
bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, everrorcb,
void *cbarg);
void
bufferevent_free(struct bufferevent *bufev);
int
bufferevent_write(struct bufferevent *bufev, void *data, size_t size);
int
bufferevent_write_buffer(struct bufferevent *bufev,
struct evbuffer *buf);
size_t
bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
int
bufferevent_enable(struct bufferevent *bufev, short event);
int
bufferevent_disable(struct bufferevent *bufev, short event);
void
bufferevent_settimeout(struct bufferevent *bufev, int timeout_read,
int timeout_write);
int
bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
struct evbuffer *
evbuffer_new(void);
void
evbuffer_free(struct evbuffer *buf);
int
evbuffer_add(struct evbuffer *buf, const void *data, size_t size);
int
evbuffer_add_buffer(struct evbuffer *dst, struct evbuffer *src);
int
evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...);
int
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);
void
evbuffer_drain(struct evbuffer *buf, size_t size);
int
evbuffer_write(struct evbuffer *buf, int fd);
int
evbuffer_read(struct evbuffer *buf, int fd, int size);
u_char *
evbuffer_find(struct evbuffer *buf, const u_char *data, size_t size);
char *
evbuffer_readline(struct evbuffer *buf);
struct evhttp *
evhttp_new(struct event_base *base);
int
evhttp_bind_socket(struct evhttp *http, const char *address,
u_short port);
void
evhttp_free(struct evhttp *http);
int (*event_sigcb)(void);
阅读(4109) | 评论(0) | 转发(0) |