libevent
Posted orejia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libevent相关的知识,希望对你有一定的参考价值。
背景
源码版本:2.1.11-stable
核心思想:Reactor模型(事件驱动)
处理的事件类型:网络IO读写,定时器,信号
reactor模型
它是一种“事件驱动”机制。程序想处理某个事件,需要提供相应的接口并注册到reactor上;如果相应的事件发生,reactor将主动调用此事件注册的接口,这些接口也称为“回调函数”。
使用libevent也是向libevent框架注册相应的事件和回调函数;当这些被注册的事件发生时,libevent会调用这些回调函数处理相应的事件。
reactor模型的组件:
- 事件源
- reactor框架
- 事件多路复用机制
- 事件处理程序
事件源:
就是socket套接字,程序需要在套接字上注册所关心的事件,如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》
以上是关于libevent的主要内容,如果未能解决你的问题,请参考以下文章