libevent入门教程

首先给出官方文档吧: http://libevent.org ,首页有个Programming with Libevent,里面是一节一节的介绍libevent,但是感觉信息量太大了,而且还是英文的-。-(当然,如果想好好用libevent,看看还是很有必要的),还有个Reference,大致就是对各个版本的libevent使用doxgen生成的文档,用来查函数原型和基本用法什么的。

下面的来着文档:http://www.wangafu.net/~nickm/libevent-book

Libevent is divided into the following components:

evutil

Generic functionality to abstract out the differences between different platforms' networking implementations.

event and event_base

This is the heart of Libevent. It provides an abstract API to the various platform-specific, event-based nonblocking IO backends. It can let you know when sockets are ready to read or write, do basic timeout functionality, and detect OS signals.

bufferevent

These functions provide a more convenient wrapper around Libevent’s event-based core. They let your application request buffered reads and writes, and rather than informing you when sockets are ready to do, they let you know when IO has actually occurred.

The bufferevent interface also has multiple backends, so that
it can take advantage of systems that provide faster ways to do
nonblocking IO, such as the Windows IOCP API.
evbuffer

This module implements the buffers underlying bufferevents, and provides functions for efficient and/or convenient access.

evhttp

A simple HTTP client/server implementation.

evdns

A simple DNS client/server implementation.

evrpc

A simple RPC implementation.

Setting up the Libevent library

Libevent has a few global settings that are shared across the entire process. These affect the entire library.

You must make any changes to these settings before you call any other part of the Libevent library. If you don’t, Libevent could wind up in an inconsistent state.

Memory management

By default, Libevent uses the C library’s memory management functions to allocate memory from the heap. You can have Libevent use another memory manager by providing your own replacements for malloc, realloc, and free. You might want to do this if you have a more efficient allocator that you want Libevent to use, or if you have an instrumented allocator that you want Libevent to use in order to look for memory leaks.

;或者希望libevent 使用一个工具分配器,以便检查内存泄漏时,可能需要这
样做。

Interface
void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
void *(*realloc_fn)(void *ptr, size_t sz),
void (*free_fn)(void *ptr));

Here’s a simple example that replaces Libevent’s allocation functions with variants that count the total number of bytes that are allocated. In reality, you’d probably want to add locking here to prevent errors when Libevent is running in multiple threads.

Locks and threading

As you probably know if you’re writing multithreaded programs, it isn’t always safe to access the same data from multiple threads at the same time.

Libevent structures can generally work three ways with multithreading.

  • Some structures are inherently single-threaded: it is never safe to use them from more than one thread at the same time.某些结构体内在地是单线程的:同时在多个线程中使用它们总是不安全的。

  • Some structures are optionally locked: you can tell Libevent for each object whether you need to use it from multiple threads at once.某些结构体具有可选的锁:可以告知libevent 是否需要在多个线程中使用每个对象。

  • Some structures are always locked: if Libevent is running with lock support, then they are always safe to use from multiple threads at once.

    某些结构体总是锁定的:如果libevent 在支持锁的配置下运行,在多个线程中使用它们
    总是安全的。

To get locking in Libevent, you must tell Libevent which locking functions to use. You need to do this before you call any Libevent function that allocates a structure that needs to be shared between threads.

If you are using the pthreads library, or the native Windows threading code, you’re in luck. There are pre-defined functions that will set Libevent up to use the right pthreads or Windows functions for you.

为获取锁,在调用分配需要在多个线程间共享的结构体的libevent 函数之前,必须告知
libevent 使用哪个锁函数。

如果使用pthreads 库,或者使用Windows 本地线程代码,那么你是幸运的:已经有设置
libevent 使用正确的pthreads 或者Windows 函数的预定义函数。

转: libevent简单介绍

1      简介

主页:http://www.monkey.org/~provos/libevent/

libevent是一个事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。

编译库代码,编译脚本会判断OS支持哪种类型的事件机制(select、epoll或kqueue),然后条件编译相应代码,供上层使用的接口仍然是保持统一的。

libevent支持用户使用三种类型的事件,分别是网络IO、定时器、信号三种。定时器的数据结构使用最小堆(Min Heap),以提高效率。网络IO和信号的数据结构采用了双向链表(TAILQ)。在实现上主要有3种链表:EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEOUT,一个ev在这3种链表之间被插入或删除,处于EVLIST_ACTIVE链表中的ev最后将会被调度执行。

有许多开源项目使用libevent,例如memcached。使用libevent,使得memcached可以适应多种操作系统。Libevent对底层异步函数提供了较薄封装,库本身没有消耗过多性能;另外,使用堆排序管理定时器队列,提供了较高的性能。

2      使用介绍

2.1   网络IO

2.1.1  代码例子

//事件回调处理函数

Static void MyCallBack(const int fd, constshort which, void *arg)

{

If(EV_READ==which){

//读事件处理

}

……

}

Int main(int argc, char** argv)

{

//初始化libevent

struct event_base *pEventBase;

pEventBase =event_init();

intsock=socket(……);

struct eventevent;

event_set(&event , sock, EV_READ | EV_PERSIST,MyCallBack, (void*)0 );

event_base_set(pEventBase, &event);

event_add(&event, 0);

event_base_loop(pEventBase, 0);

Return0;

}

2.1.2  基本函数介绍

event_init:初始化libevent库。

event_set:赋值structevent结构。可以用event_add把该事件结构增加到事件循环,用event_del从事件循环中删除。支持的事件类型可以是下面组合:EV_READ(可读),  EV_WRITE(可写),EV_PERSIST(除非调用event_del,否则事件一直在事件循环中)。

event_base_set:修改structevent事件结构所属的event_base为指定的event_base。Libevnet内置一个全局的event_base结构。多个线程应用中,如果多个线程都需要一个libevent事件循环,需要调用event_base_set修改事件结构基于的event_base。

event_add:增加事件到事件监控中。

event_base_loop:事件循环。调用底层的select、poll或epoll等,如监听事件发生,调用事件结构中指定的回调函数。

2.2   定时器

2.2.1  代码例子

struct event g_clockevent;

struct event_base *g_pEventBase;

void clock_handler(const int fd, constshort which, void *arg)

{

staticbool initialized = false;

if(initialized) {

evtimer_del(&g_clockevent);

}

else {

initialized= true;

}

evtimer_set(&g_clockevent, clock_handler, (void*) 0);

//定时器时间

structtimeval t ;

t.tv_sec=1;

t.tv_usec=0;

event_base_set(g_pEventBase, &me->m_clockevent);

if(evtimer_add(&clock_handler, &t) == -1){

return;

}

//自定义事件处理

.....

}

int main(int argv, char** argc)

{

g_pEventBase=event_init();

clock_handler(0,0,(void*)0);

return0;

}

2.2.2  基本函数介绍

evtimer_set: 设置定时器事件。

evtimer_add: 增加定时器时间。

3      源代码简介

Libevent在底层select、pool、kqueue和epoll等机制基础上,封装出一致的事件接口。可以注册可读、可写、超时等事件,指定回调函数;当事件发生后,libevent调用回调函数,可以在回调函数里实现自定义功能。前面例子已经展现了如何使用libevent接口。

本节探讨一下libevent实现机制。

3.1   重要结构体

struct eventop:对select/pool/epoll/kqueue等底层函数,按照该结构提供的接口方式,封装接口统一的函数。

struct eventop {

constchar *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 */

intneed_reinit;

};

struct event_base:相当于一个事件池。一个线程一个。使用提供的API,把需要监控的事件结构加入到该事件池中。

struct event_base {

conststruct eventop *evsel;   //指向编译时选择的一个select/pool/epoll/kqueue接口封装对象。

void*evbase;

intevent_count;            /* counts numberof total events */

intevent_count_active;  /* counts number ofactive events */

intevent_gotterm;         /* Set to terminateloop */

intevent_break;            /* Set toterminate loop immediately */

/*active event management */

structevent_list **activequeues; //活动事件队列

intnactivequeues;

/*signal handling info */

structevsignal_info sig;

structevent_list eventqueue;  //监听事件队列

structtimeval event_tv;

structmin_heap timeheap; //定时器时间堆

structtimeval tv_cache;

};

线程事件循环使用底层机制异步监控事件。

struct event:事件结构。

struct event {

TAILQ_ENTRY(event) ev_next;

TAILQ_ENTRY(event) ev_active_next;

TAILQ_ENTRY(event) ev_signal_next;

unsignedint min_heap_idx;   /* for managingtimeouts */

structevent_base *ev_base;  //事件输入的evnet_base

intev_fd;

shortev_events;

shortev_ncalls;

short*ev_pncalls;   /* Allows deletes incallback */

structtimeval ev_timeout;

intev_pri;             /* smaller numbers arehigher priority */

void(*ev_callback)(int, short, void *arg);  //回调函数

void*ev_arg;

intev_res;             /* result passed toevent callback */

intev_flags;

};

3.2   主要函数介绍

按照使用libevnet库顺序,看一下相关函数做什么操作。

3.2.1  event_init

调用event_base_new,初始化struct event_base对象。

event_base_new里做了如下工作:

1、 申请内存

2、 初始化定时器堆和事件队列

3、 为event_base对象选择底层事件函数封装对象。根据编译选项,初始化eventops全局对象。该对象存放指向底层select/pool/epoll等功能的封装函数。

4、 初始化活动队列。

3.2.2  event_set

初始化structevent对象。

1、 把参数中指定初始化的事件对象的ev_base指向全局的current_base。

2、 赋值回调函数、描述符、监视事件等变量。

3.2.3  event_base_set

把struct event对象指向的event_base对象赋值为指定的对象。

event_set函数把event对象的ev_base指向全局的current_base,多线程环境下,如需要用自己的event_base对象,需要调用event_base_set重新指定event_base对象。

3.2.4  event_add

增加指定event到监控池里。

1、 对于读、写、信号事件,调用封装的add函数,调用底层select/pool/epoll相关函数,增加到操作系统事件监控里。对于epoll,调用的是epoll_add函数。Epoll_add函数调用epoll_ctl添加事件监控,libevent使用水平触发方式。把监听时间加入到event_base的事件队列中。

2、 对应定时器事件,加入到event_base的定时器最小堆里。

3、 对信号事件,调用evsignal_add,加入事件处理队列中。

3.2.5  event_base_loop

事件循环,事件发生后,调用相应回调函数。

1、 计算最近的超时时间:定时器最小堆按照超时时间排序,取最小的超时时间;如已有活动事件或指定不阻塞,超时时间为0。

2、 调用dispatch。对epoll,对应epoll_dispatch函数。该函数调用epoll_wait监控指定事件。

3、 把到了超时时间的时间加入到活动事件队列。从超时时间最小堆中依次取最小超时时间和当前时间比较,对小于/等于当前时间的事件,加入到活动事件队列。

4、 循环调用活动事件队列中所有事件的回调函数。

epoll_dispatch:

1.      计算epoll_wait函数需要的超时时间,把时间转换成微妙。

2.      如epoll_wait被信号中断,把相应信号对应的事件加入到活动事件队列。

3.      如监视的描述上发生了特定事件,把相应事件对象加入到活动事件队列。

更多:http://blog.csdn.net/funkri/article/details/9352955
参考:http://blog.csdn.net/mafuli007/article/details/7476014

上一篇:华为-OSPF动态路由上网案例


下一篇:数值型(Math、Random、BigInteger、BigDecimal)