当前位置:   article > 正文

Libevent简介和使用

libevent

Libevent是一个用C语言编写的基于事件触发的开源高性能网络库。著名的分布式缓存软件memecached也是基于libevent,适用于windows,linux,ios等多种平台。大量用到回调函数(函数指针)的方法。于此类似的有ACE,ASIO。

优点
1.libevent是一个事件触发的网络库。专注与网络
2.跨平台。
3.使用select,dev/poll(Solaris),epoll(linux),kqueue(freebsd),IOCP(windows)等系统调用管理事件机制(IO多路复用技术)。
4.支持I/O,定时器,信号等事件。(统一事件源)
Libevent的组件和库
1.evtil:用于抽象不同的平台的网络实现。
2.event,event_base为libevent的核心,为不同的平台下基于事件的非阻塞IO提供了接口。
3.bufferevent对libevent的基于事件的核心的封装。应用程序的读写请求是基于缓冲区的。
4.Evbuffer为bufferevent实现的缓冲区。
5.Evhttp:一个简单的http client/server 的实现。
6.Evdns:一个简单的dns client/server的实现。
7.Evrpc:一个简单的rpc实现。

Libevent的功能
Libevent提供了事件通知,io缓存事件,定时器,超时,异步解析dns,事件驱动的http server以及一个rpc框架。
事件通知:当文件描述符可读可写时将执行回调函数。
IO缓存:缓存事件提供了输入输出缓存,能自动的读入和写入,用户不必直接操作IO。
定时器:libevent提供定时器的机制,能够在一定时间间隔之后执行回调函数。
信号:触发信号,执行回调。
异步解析dns:一部解析dns服务器的dns解析函数集。
Rpc客户端服务器框架:能自动的封装和解封装数据结构。
这里写图片描述

Reactor反应堆模式
整个libevent就是一个Reactor。
Reactor是一种事件处理的机制。
普通函数的调用机制:
程序调用函数—》函数执行,程序等待—》函数将结果和控制权返回 程序—》程序继续执行。(在函数没有返回的过程中,程序一直阻塞)。
Reactor模式的做法:
逆置了普通函数的事件处理流程,应用程序需要提供相应的接口并注册到reactor上,如何相应的时间发生,reactor会主动调用应用程序注册的接口,处理事件,这些接口就是“回调函数”。
Reactor的框架
组件:事件源,reactor框架,多路复用机制,事件处理。
1》事件源—Handle(句柄集)
管理文件描述符或者信号值的机制,即统一了三类事件:IO,信号量,定时器

2》事件多路分发机制—–event demultiplexer
OS提供的IO多路复用机制,程序首先将其关心的句柄及其事件注册在event demultiplexer上,事件到达,event demultiplexer就会发出通知“一个或多个事件就绪”,程序收到通知后,就会对事件进行处理。对应于结构体eventop。

3》反应器—Reactor
事件管理的接口,内部使用event demultiplexer注册注销事件,并运行事件循环,当有事件进入“就绪”状态,调用注册事件的回调函数处理事件。对应于结构体event_base。

4》事件处理程序–Event Hander
事件源只是来对多个fd进行管理,而真正对三类事件的封装则是在Event Hander里面,它有一组接口,每个接口对应一种事件类型,供Reactor在相应的事件发生时调用,执行相应的事件处理。对应结构体event。

#define TAILQ_ENTRY(type)
struct {
    struct type *tqe_next;
    struct type **tqe_prev;
};
  • 1
  • 2
  • 3
  • 4
  • 5
//TAILQ_HEAD(event_list,event)
#define TAILQ_HEAD(name,type)
struct name{
    struct type  *tqh_first;
    struct type **tqh_last;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
struct event{
    TAILQ_ENTRY(event) ev_active_next;
    TAILQ_ENTRY(event) ev_next;

    struct event_base *ev_base;
    int ev_fd;  //evutil_socket_t

    union{
        TAILQ_ENTRY(event) ev_next_with_common_timeout;
        int min_heap_idx;
    }ev_timeout_pos;

    union{
        struct {
            TAILQ_ENTRY(event) ev_io_next;
            struct timeval ev_timeout;
        }ev_io;

        struct{
            TAILQ_ENTRY(event) ev_signal_next;
            short ev_ncalls;
            short *ev_pncalls;
        }v_signal;
    }_ev;

    short ev_events;//event类型
    short ev_res;   //
    short ev_flags; //event状态
    unsigned char ev_pri;      //ev_uint8_t
    //ev_closure的作用就是告诉在事件处理时调用不同的处理函数。
    unsigned char ev_closure; //回调函数的类型
    struct timeval ev_timeout; 

    void(*ev_callback)(int, short, void *arg);
    void *ev_arg;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
//ev_events; //event类型
#define EV_TIMEOUT   0x01
#define EV_READ      0x02
#define EV_WRITE     0x04
#define EV_SIGAL     0x08
#define EV_PERSIST   0x10  //永久事件
#define EV_ET        0x20  //ET边缘触发

//ev_flags; //event状态
#define EVLIST_TIMEOUT  0x01  //事件在堆中
#define EVLIST_INSERTED 0x02  //事件已经注册到链表中
#define EVLIST_SIGNAL   0x04  //
#define EVLIST_ACTIVE   0x08  //事件激活链表中
#define EVLIST_INTERNAL 0x10  //
#define EVLIST_INIT     0x80  //事件已经初始化

//ev_closure; //回调函数的类型
#define EV_CLOSURE_NONE     0 //其他
#define EV_CLOSURE_SIGNAL   1 //signal
#define EV_CLOSURE_PERSIST  2 //永久
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

struct eventop{
    const char *name;//IO多路复用机制
    void *(*init)(struct event_base *); 
    void (*add)(struct base_base *, int fd, short old, short events, void *fdinfo);
    void (*del)(struct base_base *, int fd, short old, short events, void *fdinfo);
    void (*dispath)(struct event_base*, struct timeval *);
    void (*dealloc)(struct event_base *);
    int need_reinit;//是否需要重新初始化
    enum event_method_feature feature; //
    size_t fdinfo_len;
};

enum event_method_feature{
    EV_FEATURE_ET = 0x01, //kqueue
    EV_FEATURE_01 = 0x02, //kqueue,epoll,devpoll
    EV_FEATURE_FDS= 0x04  //kqueue,epoll,devpoll,select,poll,
};
//evport,win32 对上设置为0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
/*
 * 当我们创建一个event_base时,libevent会帮我们选择最快的IO复用方式
 * event_base_get_method(base);查看libevent具体选择了哪个IO复用方式
*/
struct event_base{
    void *evbase;
    const struct eventop *evsel;
    const struct eventop *evsigsel;
    struct evsig_info sig;

    int event_count;
    int event_count_active;

    struct event_list *activequeues;
    int nactivequeues;

    struct event_io_map io;
    struct event_signal_map sigmap;
    struct event_list eventqueue;

    struct timeval event_tv;
    struct min_heap timeheap;
    struct timeval tv_cache;

};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/742735
推荐阅读
相关标签
  

闽ICP备14008679号