1.文档链接
Libevent Reference
Libevent深入浅出
2.安装
# 查询libevent库
sudo apt-cache search libevent
# 安装相关库
sudo apt-get install libevent-2.1-7 libevent-dev
# 查询是否安装成功
apt list --installed|grep libevent
3.测试
#include <stdio.h>
#include <time.h>
#include <event.h>
struct event ev;
struct timeval tv;
time_t now;
void time_cb(int fd, short event, void *argc)
{
time(&now);
printf("timer wakeup:%ld\n", now);
event_add(&ev, &tv);
}
int main(void)
{
struct event_base *base = event_init(); /* 1.初始化libevent库,初始化一个Reactor实例 */
tv.tv_sec = 3;
tv.tv_usec = 0;
evtimer_set(&ev, time_cb, NULL); /* 2.初始化时间event, 设置回调函数和关注的事件 */
event_base_set(base, &ev); /* 3.设置event从属的event_base */
event_add(&ev, &tv); /* 4.添加事件, Reactor::register_handler() */
printf("start event loop1...\n");
event_base_dispatch(base); /* 5.开启事件循环,等待就绪事件并执行事件处理 */
return 0;
}
4. Event
4.1 event结构体
struct event {
TAILQ_ENTRY (event) ev_next;
TAILQ_ENTRY (event) ev_active_next;
TAILQ_ENTRY (event) ev_signal_next;
unsigned int min_heap_idx; /* for managing timeouts */
struct event_base *ev_base;
int ev_fd;
short ev_events; // 事件类型
short ev_ncalls;
short *ev_pncalls; /* Allows deletes in callback */
struct timeval ev_timeout;
int ev_pri; /* smaller numbers are higher priority */
void (*ev_callback)(int, short, void *arg);
void *ev_arg;
int ev_res; /* result passed to event callback,当前激活事件的类型 */
int ev_flags; // 用于标记event信息的字段,表明其当前的状态
};
4.2 libevent中定义的事件类型:
// ev_events
#define EV_TIMEOUT 0x01 // 定时事件
#define EV_READ 0x02 // I/O事件
#define EV_WRITE 0x04 // I/O事件
#define EV_SIGNAL 0x08 // 信号
#define EV_PERSIST 0x10 /* 永久事件 Persistant event */
// eb_flags
#define EVLIST_TIMEOUT 0x01 // event在time堆中
#define EVLIST_INSERTED 0x02 // event在已注册事件链表中
#define EVLIST_SIGNAL 0x04 // 未见使用
#define EVLIST_ACTIVE 0x08 // event在激活链表中
#define EVLIST_INTERNAL 0x10 // 内部使用标记
#define EVLIST_INIT 0x80 // event 已被初始化
4.3 事件设置的接口函数
/* 1.设置事件 ev 绑定的文件描述符或者信号,对于定时事件,设为-1 即可;
2.设置事件类型,比如 EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL 等;
3.设置事件的回调函数以及参数 arg;
4.初始化其它字段,比如缺省的 event_base 和优先级 */
void event_set(struct event *ev, int fd, short events,
void (*callback)(int, short, void *), void *arg)
/* 设置 event ev 将要注册到的 event_base;
libevent 有一个全局 event_base 指针 current_base,默认情况下事件 ev
将被注册到 current_base 上,使用该函数可以指定不同的 event_base;
如果一个进程中存在多个 libevent 实例,则必须要调用该函数为 event 设
置不同的 event_base;*/
int event_base_set(struct event_base *base, struct event *ev)
/* 设置event ev的优先级,注意的一点:当ev正处于就绪状态
时,不能设置,返回-1。*/
int event_priority_set(struct event *ev, int pri)
5.事件处理框架
5.1 event_base
// event-internal.h
struct event_base {
const struct eventop *evsel; // 类, I/O demultiplex机制统一封装的eventop结构
void *evbase; // 实例对象
int event_count; /* counts number of total events */
int event_count_active; /* counts number of active events */
int event_gotterm; /* Set to terminate loop */
int event_break; /* Set to terminate loop immediately */
/* active event management */
struct event_list **activequeues;
int nactivequeues;
/* signal handling info */
struct evsignal_info sig;
struct event_list eventqueue;
struct timeval event_tv;
struct min_heap timeheap;
struct timeval tv_cache;
};
struct eventop {
const char *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 */
int need_reinit;
};
5.2 接口函数
// 创建一个event_base对象
struct event_base *event_init(void);
struct event_base *event_base_new(void);
int event_add(struct event *ev, const struct timeval *timeout); // 注册事件
int event_del(struct event *ev); // 删除事件
int event_base_loop(struct event_base *base, int loops); // 事件处理主循环
void event_active(struct event *event, int res, short events);
void event_process_active(struct event_base *base);
6.集成信号处理
6.1 Signal集成到框架
1.集成策略 —— socket pair
一个socket对,包含两个 socket,一个读 socket,一个写 socket。
int evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
// Libevent 中 Signal 事件的管理 evsignal.h
struct evsignal_info {
struct event ev_signal;
int ev_signal_pair[2];
int ev_signal_added;
volatile sig_atomic_t evsignal_caught;
struct event_list evsigevents[NSIG];
sig_atomic_t evsigcaught[NSIG];
#ifdef HAVE_SIGACTION
struct sigaction **sh_old;
#else
ev_sighandler_t **sh_old;
#endif
int sh_old_max;
};