zoukankan      html  css  js  c++  java
  • libevent

    背景

    源码版本:2.1.11-stable

    核心思想:Reactor模型(事件驱动)

    处理的事件类型:网络IO读写,定时器,信号

    reactor模型

    它是一种“事件驱动”机制。程序想处理某个事件,需要提供相应的接口并注册到reactor上;如果相应的事件发生,reactor将主动调用此事件注册的接口,这些接口也称为“回调函数”。

    使用libevent也是向libevent框架注册相应的事件和回调函数;当这些被注册的事件发生时,libevent会调用这些回调函数处理相应的事件。

    reactor模型的组件:

    • 事件源
    • reactor框架
    • 事件多路复用机制
    • 事件处理程序

    事件源:

    事件源用一个整型变量表示,libevent支持的事件源分两类:一类是大于0的文件描述符,用于socket通信;另一类是小于0,有定时器、信号和用户自定义事件。

    • 通信套接字,通常注册它的IO读写事件

    事件多路复用机制(event demultiplexer):

      select 、poll、epoll等,;

      程序首先将其注册了关心事件的回调的套接字注册到event demultiplexer上,

      当有事件到达时,event demultiplexer会向已经注册的套接字集合发出通知 “一个或多个事件已经就绪”;

      对应到libevent, 使用了结构体eventop对select、poll等进行了封装,以统一接口来实现IO多路复用机制;

    reactor:

      事件管理的接口,内部通过event demultiplexer进行事件的注册和注销操作;并运行事件循环,当有事件进入“就绪”状态时,就调用注册事件的回调函数来处理事件;

      对应到libevent,就是结构体event_base;

    事件处理程序:

      事件处理程序提供一级接口,每个接口对应一种类型的事件,供reactor在相应事件发生时调用;

      对应到libevent,就是结构体event;

    库的全局设置

    • 日志消息
    • 处理致使错误
    • 内存管理
    • 锁和线程
    • 调试锁的使用
    • 调试事件的使用
    • 检测库的版本
    #define EVENT_LOG_DEBUG 0
    #define EVENT_LOG_MSG   1
    #define EVENT_LOG_WARN  2
    #define EVENT_LOG_ERR   3
    typedef void (*event_log_cb)(int severity, const char *msg);
    void event_set_log_callback(event_log_cb cb);

      手写日志回调,将其作为参数并调用event_set_log_callback(),将覆盖日志的默认行为;

      日志默认输出到stderr, 再次调用event_set_log_callback()并传参NULL将恢复默认行为;

    typedef void (*event_fatal_cb)(int err);
    void
    event_set_fatal_callback(event_fatal_cb cb);

      程序执行期间,遇到致使错误的默认行为是退出程序;

      设置退出回调,可在程序异常退出前执行回调;

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

      替换默认的内存管理函数malloc, realloc, free

    const char *event_get_version(void);
    ev_uint32_t event_get_version_number(void);

      获取libevent版本信息

    具体信息,参考《从一万英尺下看libevent》

    event_base相关源码解析

    struct event_base
    • 作用:保存一个libevent调度回路的信息和状态(监视所有就绪事件和未决事件,并通知就绪事件)
    • 特点:是一个不透明结构体
    • 分配方法:event_base_new() | event_base_new_with_config()
    struct event_base *event_base_new(void);
    • 功能:分配一个默认的event_base结构体
    • 返回:成功返回一个具有默认设置的指针,失败返回NULL
    struct event_base *event_base_new_with_config(const struct event_config *);
    • 创建一个带有配置属性的event_base,需要传入event_config结构体
    • 成功返回带配置属性的指针,失败返回NULL
    struct event_config *event_config_new(void);
    • 功能:先创建event_config结构体,它可以保存event_base属性
    • 返回:成功返回可用结构体指针,失败返回NULL
    int event_config_avoid_method(struct event_config *cfg, const char *method);
    • 功能:禁用某种方法
    int event_config_require_features(struct event_config *cfg, int feature);
    enum event_method_feature { //flag
      EV_FEATURE_ET = 0x01,        //边沿触发
      EV_FEATURE_O1 = 0x02, //添加、删除单个事件,或者确定哪个事件是激活状态的操作的时间复杂度是O(1)
      EV_FEATURE_FDS = 0x04, //允许文件描术符和套接字
      EV_FEATURE_EARLY_CLOSE = 0x08//在不需要检测所有未激活连接的情况,检测某个连接是否关闭
    }
    • 功能:声明某种特性
    • 返回:成功返回0,失败返回-1
    int event_config_set_flag(struct event_config *cfg, int flag);
    enum event_base_config_flag {
      EVENT_BASE_FLAG_NOLOCK = 0x01, //不分配锁
      EVENT_BASE_FLAG_IGNORE_ENV = 0x02, //不检测EVENT_* 环境变量
      EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, //仅windows可用
      EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, //超时回调执行后检测当前时间
      EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,//使用epoll_changelist特征
      EVENT_BASE_FLAG_PRECISE_TIMER = 0x20 //使用效率低但更精准的计时器
    }
    •  功能:设置event_base的工作特性
    • 返回:成功返回0,失败返回-1
    const char **event_get_supported_methods(void);
    • 功能:返回所有支持的事件通知机制
    const char *event_base_get_method(const struct event_base *);
    • 功能:返回正在使用的机制(方法)
    int event_base_get_features(const struct event_base *base);
    • 功能:检查并返回一个event_base已设置的特征属性
    void event_base_free(struct event_base *);
    • 功能:从内存删除一个event_base
    int    event_base_priority_init(struct event_base *, int);
    • 功能:设置最大优先级数目
    int event_reinit(struct event_base *base);
    • fork后重新初始化event_base

    事件循环相关源码解析

    事件循环过程中,libevent是在等待并通知已经注册并发生的事件。

    int event_base_loop(struct event_base *base, int flags)
    flags:
      #define EVLOOP_ONCE 0x01
      #define EVLOOP_NONBLOCK 0x02
      #define EVLOOP_NO_EXIT_ON_EMPTY 0x04
    • 功能:循环检查是否有注册事件被激活,并执行激活事件
    int event_base_dispatch(struct event_base *event_base)
    • 功能:一直监视未决和就绪事件,直到所有事件都没有了或者调用了 event_base_loopbreak() 或event_base_loopexit()
    • 返回:成功返回0,失败返回-1,如果没有监视的事件了返回1
    int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv);
    • 功能:在事件回调函数内部,获取event_base缓存的当前时间的近似值
    • 返回:成功返回0
    void event_base_dump_events(struct event_base *, FILE *);
    • 功能:导出event_base当前监视的事件列表到本地文件(用于程序调试)

    事件

    事件是libevent的基本操作单元,每个事件代表一组条件的集合,条件包括:

    • 文件描述符已经就绪,可读写;
    • 文件描述符变为就绪(边沿触发),可读写;
    • 超时事件;
    • 发生信号;
    • 用户触发事件;

    调用libevent函数设置事件并关联到event_base之后,该事件进入“已初始化"状态(initiailzed);

    此时,可以将其添加到event_base中,这使得其进入“未决”状态(pending);

    在未决状态下,如果触发事件的条件发生(如超时,文件描述符状态改变),则事件进入“激活”状态(active),用户注册的事件回调函数将被执行;

    如果事件配置为“持久的”(persistent),事件将保持为未决状态,否则事件不再未决;

    删除操作可心让未决事件成为非未决(已初始化)的;

    添加操作可以让非未决事件再次成为为未决的;

    创建事件

    #define EV_TIMEOUT   0x01 //超时,在将事件添加到event_base时使用
    #define EV_READ      0x02 //文件描述符可读
    #define EV_WRITE     0x04 //文件描述符可写
    #define EV_SIGNAL    0x08 //信号发生
    #define EV_PERSIST   0x10 //未决状态持久
    #define EV_ET        0x20 //边沿触发
    #define EV_FINALIZE  0x40 //非阻塞调用event_del()
    #define EV_CLOSED    0x80 //连接关闭
    typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
    event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg);
    • 功能:创建一个新事件。fd为非负时监视其读写,events是监视的事件类型的位集合
    • 返回:成功返回新事件指针,失败返回NULL
    • 说明:所有新创建的事件都处于已初始化和非未决状态

    事件的持久性

    默认情况下,事件从未决状态变成就绪状态后,事件将在执行事件回调前成为非未决状态;

    如果想让事件再次成为未决状态,可以在回调函数内部再次将其添加到event_base;

    然而,如果事件创建时设置了EV_PERSIST标志,则事件变成就绪态执行回调前不会变成非未决状态;

    如果想让未决状态事件变成非未决状态,可调用event_del()执行删除操作;

    创建只关心超时的事件

    #define evtimer_new(b, cb, arg)        event_new((b), -1, 0, (cb), (arg))
    #define evtimer_add(ev, tv)            event_add((ev), (tv))
    #define evtimer_del(ev)                event_del(ev)
    #define evtimer_pending(ev, tv)        event_pending((ev), EV_TIMEOUT, (tv))
    #define evtimer_initialized(ev)        event_initialized(ev)

    使用这些宏函数,可以使设置纯超时事件更简便,当然,你也可以直接使用原生操作函数

    创建信号事件

    #define evsignal_add(ev, tv)        event_add((ev), (tv))
    #define evsignal_del(ev)            event_del(ev)
    #define evsignal_pending(ev, tv)    event_pending((ev), EV_SIGNAL, (tv))
    #define evsignal_initialized(ev)    event_initialized(ev)

    让事件变成未决状态和非未决状态

    int event_add(struct event *ev, const struct timeval *timeout);
    int event_del(struct event *ev)

     设置事件的优先级

    int event_priority_set(struct event *ev, int pri);

    示例:

    获取事件状态

    int event_pending(const struct event *ev, short event, struct timeval *tv);

      功能:判断给定事件是否是未决或就绪状态

    evutil_socket_t event_get_fd(const struct event *ev);

      功能:返回事件的文件描述符

    #define event_get_signal(ev) ((int)event_get_fd(ev))

      功能:返回事件的信号值

    struct event_base *event_get_base(const struct event *ev);

      功能:返回事件的event_base

    short event_get_events(const struct event *ev);

      功能:返回事件的标志

    event_callback_fn event_get_callback(const struct event *ev);

      功能:返回事件的回调函数

    void *event_get_callback_arg(const struct event *ev);

      功能:返回事件回调函数的参数

    void event_get_assignment(const struct event *event,
        struct event_base **base_out, evutil_socket_t *fd_out, short *events_out,
        event_callback_fn *callback_out, void **arg_out);

      功能:返回上述所有

    创建一次触发事件

    int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *);

     手动激活事件

    void event_active(struct event *ev, int res, short ncalls);

    参考

    来自官方文档《从一万英尺外看libevent》

  • 相关阅读:
    day06 tar命令使用,vim简单操作以及linux开机过程
    day05 创建用户过程、文件夹,文件等权限修改等
    简单算法
    day04
    day03
    Vim常用快捷键
    day02
    ssh注解开发
    spring07 JDBC
    spring06Aop
  • 原文地址:https://www.cnblogs.com/orejia/p/12127513.html
Copyright © 2011-2022 走看看