🔑 核心概念与API - libevent源码深度解析系列(四)
2295 字
11 分钟
🔑 核心概念与API - libevent源码深度解析系列(四)
🧠 核心概念与API
一、事件编程模型
在事件驱动编程模型中,主要有三个核心组件:
- 🔷 事件源(Event Source):产生事件的对象,如网络连接、文件描述符等。
- 🔷 事件处理器(Event Handler):负责处理事件的回调函数。
- 🔷 事件循环(Event Loop):负责调度事件处理器的中心组件。
1.1 事件驱动模型流程图
┌─────────────────────────────────────────────────────────┐│ 事件循环 (event_base) │├─────────────────────────────────────────────────────────┤│ 1. 初始化事件基 ││ 2. 注册事件 (event_new + event_add) ││ 3. 进入事件循环 (event_base_dispatch) ││ ├─ 等待事件触发 ││ ├─ 分发事件到对应的处理器 ││ ├─ 执行事件回调 ││ └─ 重复上述步骤 ││ 4. 退出事件循环 │└─────────────────────────────────────────────────────────┘1.2 事件处理流程
┌─────────────────────────────────────────────────────────┐│ 事件处理流程 │├─────────────────────────────────────────────────────────┤│ 1. 事件源产生事件 (如网络数据到达) ││ 2. I/O多路复用机制检测到事件 ││ 3. event_base获取就绪事件 ││ 4. 查找对应的event结构体 ││ 5. 将event添加到活跃事件队列 ││ 6. 按优先级处理活跃事件 ││ 7. 调用事件的回调函数 ││ 8. 如果是持久事件(EV_PERSIST),重新添加到事件队列 │└─────────────────────────────────────────────────────────┘二、事件基(Event Base)
在 libevent 中,事件基(Event Base)是一个核心概念,它是事件驱动编程模型中的事件循环的实现。事件基负责管理所有注册的事件,并在事件发生时调度相应的事件处理器。
2.1 主要功能
- 🔶 事件注册:将事件注册到事件基
- 🔶 事件调度:在事件发生时调度相应的事件处理器
- 🔶 事件循环:通过
event_base_dispatch()启动事件循环,处理事件
2.2 event_base_new API 详解
struct event_base *event_base_new(void);返回值
- 成功:返回事件基结构体指针
- 失败:返回 NULL
2.3 event_base_new_with_config API 详解
struct event_base *event_base_new_with_config(const struct event_config *cfg);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| cfg | const struct event_config* | 事件基配置结构体 |
返回值
- 成功:返回事件基结构体指针
- 失败:返回 NULL
2.4 event_base_dispatch API 详解
int event_base_dispatch(struct event_base *base);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| base | struct event_base* | 要启动的事件基 |
返回值
- 成功:返回 0
- 失败:返回 -1
2.5 event_base_loop API 详解
int event_base_loop(struct event_base *base, int flags);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| base | struct event_base* | 要启动的事件基 |
| flags | int | 循环标志,如 EVLOOP_ONCE、EVLOOP_NONBLOCK 等 |
返回值
- 成功:返回 0
- 失败:返回 -1
2.6 event_base_loopexit API 详解
int event_base_loopexit(struct event_base *base, const struct timeval *tv);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| base | struct event_base* | 要退出的事件基 |
| tv | const struct timeval* | 退出延迟时间,NULL表示立即退出 |
返回值
- 成功:返回 0
- 失败:返回 -1
2.7 event_base_loopbreak API 详解
int event_base_loopbreak(struct event_base *base);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| base | struct event_base* | 要中断的事件基 |
返回值
- 成功:返回 0
- 失败:返回 -1
2.8 event_base_free API 详解
void event_base_free(struct event_base *base);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| base | struct event_base* | 要释放的事件基 |
2.9 基本操作示例
// 创建事件基struct event_base *base = event_base_new();if (!base) { fprintf(stderr, "Failed to create event base\n"); return 1;}
// 带配置创建事件基struct event_config *cfg = event_config_new();event_config_require_features(cfg, EV_FEATURE_ET);struct event_base *base_with_config = event_base_new_with_config(cfg);event_config_free(cfg);
// 启动事件循环(阻塞模式)event_base_dispatch(base);
// 启动事件循环(非阻塞模式)event_base_loop(base, EVLOOP_NONBLOCK);
// 延迟退出事件循环struct timeval tv = {5, 0}; // 5秒后退出event_base_loopexit(base, &tv);
// 立即中断事件循环event_base_loopbreak(base);
// 释放事件基event_base_free(base);event_base_free(base_with_config);三、事件(Event)
在 libevent 中,事件(Event)代表了一个具体的事件源及其相关的事件处理器。事件可以绑定到不同的事件源上,如文件描述符、网络套接字等。
3.1 event_new API 详解
struct event *event_new(struct event_base *base, evutil_socket_t fd, short flags, event_callback_fn callback, void *arg);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| base | struct event_base* | 事件所属的事件基 |
| fd | evutil_socket_t | 事件绑定的文件描述符,对于定时器事件设为-1 |
| flags | short | 事件标志,如 EV_READ、EV_WRITE、EV_PERSIST 等 |
| callback | event_callback_fn | 事件触发时的回调函数 |
| arg | void* | 传递给回调函数的参数 |
返回值
- 成功:返回事件结构体指针
- 失败:返回 NULL
回调函数签名
typedef void (*event_callback_fn)(evutil_socket_t fd, short events, void *arg);| 参数 | 类型 | 说明 |
|---|---|---|
| fd | evutil_socket_t | 事件绑定的文件描述符 |
| events | short | 触发的事件类型,如 EV_READ、EV_WRITE 等 |
| arg | void* | 传递给回调函数的参数 |
3.2 event_add API 详解
int event_add(struct event *ev, const struct timeval *timeout);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| ev | struct event* | 要添加的事件 |
| timeout | const struct timeval* | 超时时间,NULL表示无超时 |
返回值
- 成功:返回 0
- 失败:返回 -1
3.3 event_del API 详解
int event_del(struct event *ev);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| ev | struct event* | 要删除的事件 |
返回值
- 成功:返回 0
- 失败:返回 -1
3.4 event_free API 详解
void event_free(struct event *ev);参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| ev | struct event* | 要释放的事件 |
3.5 事件的主要属性
| 属性 | 说明 |
|---|---|
| 描述符(Descriptor) | 事件绑定的文件描述符或套接字 |
| 标志(Flags) | 表示事件类型和行为的标志位,如 EV_READ、EV_WRITE、EV_PERSIST 等 |
| 回调函数(Callback) | 事件发生时调用的函数 |
| 回调参数(Argument) | 传递给回调函数的参数 |
3.6 事件操作示例
// 创建事件struct event *ev = event_new(base, fd, EV_READ | EV_PERSIST, read_callback, arg);if (!ev) { fprintf(stderr, "Failed to create event\n"); return -1;}
// 添加事件(无超时)if (event_add(ev, NULL) < 0) { fprintf(stderr, "Failed to add event\n"); event_free(ev); return -1;}
// 添加事件(带超时)struct timeval tv = {5, 0}; // 5秒超时if (event_add(ev, &tv) < 0) { fprintf(stderr, "Failed to add event with timeout\n"); event_free(ev); return -1;}
// 删除事件if (event_del(ev) < 0) { fprintf(stderr, "Failed to delete event\n");}
// 释放事件event_free(ev);四、事件处理(Event Handling)
事件处理是 libevent 的核心功能之一。当事件发生时,事件基会调度相应的事件处理器。
void event_callback(evutil_socket_t fd, short event, void *arg) { // 处理事件}
struct event *event = event_new(base, fd, EV_READ | EV_PERSIST, event_callback, arg);event_add(event, NULL); // 添加事件五、事件标志
事件标志用于指定事件的类型和行为:
| 标志 | 值 | 说明 |
|---|---|---|
EV_TIMEOUT | 0x01 | 定时事件 |
EV_READ | 0x02 | 读事件,表示当文件描述符可读时触发事件 |
EV_WRITE | 0x04 | 写事件,表示当文件描述符可写时触发事件 |
EV_SIGNAL | 0x08 | 信号事件 |
EV_PERSIST | 0x10 | 持久事件,表示事件在触发后不会自动删除,而是继续保留在事件基中 |
EV_ET | 0x20 | 边缘触发模式,仅在数据可用时触发 |
六、定时器(Timer)
libevent 支持定时器功能,允许开发者在特定的时间间隔内执行任务。
void timer_callback(evutil_socket_t fd, short event, void *arg) { printf("Timer fired!\n");}
// -1 表示定时器不绑定到任何文件描述符struct event *timer = event_new(base, -1, EV_PERSIST, timer_callback, NULL);struct timeval delay = {5, 0}; // 设置定时器时间为 5 秒event_add(timer, &delay);七、信号处理
libevent 支持信号处理,允许开发者在接收到特定信号时执行相应的动作。
void signal_handler(evutil_socket_t fd, short event, void *arg) { printf("Signal received!\n"); event_base_loopexit(base, NULL);}
struct event *signal_event = evsignal_new(base, SIGINT, signal_handler, base);event_add(signal_event, NULL);八、多线程支持
libevent 支持多线程环境,允许开发者在多线程程序中安全地使用事件基。
event_base_mutex_lock(base);event_base_mutex_unlock(base);九、事件基的生命周期
事件基的生命周期包括创建、启动和销毁三个阶段:
- 创建:使用
event_base_new()创建事件基 - 启动:使用
event_base_dispatch()启动事件循环 - 销毁:使用
event_base_free()销毁事件基
十、示例代码
下面是一个完整的示例代码,展示了如何使用 libevent 创建一个简单的定时器:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <event2/event.h>
static void timer_callback(evutil_socket_t fd, short event, void *arg) { printf("Timer fired!\n");
// 重新调度定时器 struct event *timer = (struct event *)arg; struct timeval delay = {5, 0}; event_add(timer, &delay);}
int main() { struct event_base *base; struct event *timer;
base = event_base_new(); if (!base) { fprintf(stderr, "Failed to create event base\n"); return 1; }
timer = event_new(base, -1, EV_PERSIST, timer_callback, timer); if (!timer) { fprintf(stderr, "Failed to create timer event\n"); event_base_free(base); return 1; }
struct timeval delay = {5, 0}; event_add(timer, &delay);
event_base_dispatch(base);
event_free(timer); event_base_free(base);
return 0;}十一、使用注意事项
11.1 事件基的管理和使用
- 单线程原则:事件基(
event_base)的设计是单线程的,即一个事件基只能在一个线程中使用。如果在多线程环境下使用libevent,每个线程应有自己的事件基实例。
struct event_base *base1 = event_base_new(); // 第一个线程的事件基struct event_base *base2 = event_base_new(); // 第二个线程的事件基- 线程安全:虽然
libevent提供了一些线程安全的功能,但在多线程环境中,对事件基的操作(如添加、删除事件)必须确保线程安全。
11.2 回调函数的设计
- 非阻塞性:事件处理函数(回调函数)不应执行长时间的阻塞操作,否则会影响事件循环的效率。
- 资源管理:在事件处理函数中,应妥善管理资源,确保资源的正确释放。
11.3 定时器的使用
- 精确度:定时器的精度取决于底层操作系统提供的定时器机制。在某些情况下,定时器的触发时间可能会有所偏差。
- 循环定时器:使用
EV_PERSIST标志创建的定时器会在每次触发后自动重新调度。
其他相关资料 请移步到个人主页
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!
🔑 核心概念与API - libevent源码深度解析系列(四)
https://xutopia.top/blog/libevent-core-concepts/
