0%

libevent库

摘要

  • libevent 库 相关学习笔记
  • libevent是一个异步事件处理软件函数库,是一个提供异步事件通知的软件库。它提供了一组应用程序编程接口(API),libevent API提供的机制允许开发者为事件注册回调函数,例如文件描述符上的发生了特定事件或等待事件超时,接收到信号的事件,常规的定时器超时事件。当事件发生时,libevent实例会执行回调函数。
  • libevent在设计上是用来替代很多事件驱动网络服务器自行实现的事件循环框架的。也就是说,libevent可以用来取代网络服务器所使用的事件循环检查框架。
  • libevent现在支持 /dev/poll, kqueue, POSIX select, Windows IOCP, poll, epoll, Solaris端口。libevent对实时信号有实验性支持。libevent暴露出的API在全平台都是一致的,因此libevent支持可移值的应用程序开发,并提供操作系统上可扩展的事件通知机制。

libevent 详解

libevent 是一个开源的事件通知库,它提供了一个高效、跨平台的 API 来处理异步 I/O 操作、定时器事件和信号处理。libevent 的核心功能是支持多种 I/O 模型,允许开发者使用事件驱动的方式来开发高效、并发的网络服务应用程序。

libevent 设计的目标是简化异步编程,特别是在高并发应用中,它通过事件循环(event loop)来调度事件并通知相应的回调函数。它被广泛用于一些高性能的服务器中,尤其是那些需要高效网络通信、文件操作或信号处理的场景。

1. 核心概念

1.1 事件循环(Event Loop)

libevent 的核心是事件循环,类似于 libuvNode.js。事件循环不断地检测事件(如 I/O 操作完成、定时器到期等),并在事件发生时调用相应的回调函数。

事件循环的执行是非阻塞的,事件循环会持续运行,直到所有注册的事件都被处理完成。

1.2 事件驱动模型(Event-Driven Model)

libevent 使用事件驱动的模型来管理不同类型的事件,包括:

  • 网络 I/O 事件(例如读取或写入文件或套接字)
  • 定时器事件(例如定时任务或超时)
  • 信号事件(例如接收系统信号,如 SIGINT)
  • 文件系统事件(例如文件描述符的变化)

开发者将这些事件与对应的回调函数关联起来,一旦事件发生,libevent 就会调用回调函数处理事件。

1.3 事件源(Event Sources)

libevent 支持多种事件源,主要包括:

  • I/O 事件:用于非阻塞的 I/O 操作,如网络通信、文件操作。
  • 定时器事件:在指定时间后执行回调函数。
  • 信号事件:处理操作系统发送的信号。
  • 文件描述符事件:监控文件描述符的状态变化(例如,网络连接可读可写)。

2. libevent 的基本结构和 API

2.1 创建事件基础

在使用 libevent 时,首先需要创建一个事件基础(event_base),它是事件循环的核心对象,管理着所有的事件和调度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <event.h>
#include <stdio.h>

int main() {
struct event_base *base;
base = event_base_new(); // 创建事件基础
if (!base) {
perror("Failed to create event base");
return 1;
}

// 在此处设置事件
event_base_dispatch(base); // 启动事件循环

event_base_free(base); // 清理资源
return 0;
}

2.2 创建和管理事件

libevent 提供了 event 对象来封装单个事件。通过 event_new 函数创建事件,并通过 event_add 将其添加到事件基础中。

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
#include <event.h>
#include <stdio.h>
#include <unistd.h>

void on_read(int fd, short event, void *arg) {
printf("Read event triggered on fd %d\n", fd);
}

int main() {
struct event_base *base;
struct event *ev;
int fd = 0; // 标准输入

base = event_base_new(); // 创建事件基础

// 创建一个 I/O 事件,监听标准输入(fd = 0)是否可读
ev = event_new(base, fd, EV_READ | EV_PERSIST, on_read, NULL);
event_add(ev, NULL); // 将事件添加到事件循环

event_base_dispatch(base); // 启动事件循环

event_free(ev); // 清理资源
event_base_free(base); // 清理事件基础
return 0;
}

2.3 定时器事件

可以使用 event_new 创建定时器事件,并使用 event_add 来添加事件。定时器事件会在指定时间触发回调。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <event.h>
#include <stdio.h>

void on_timeout(int fd, short event, void *arg) {
printf("Timer expired\n");
}

int main() {
struct event_base *base;
struct event *ev;

base = event_base_new(); // 创建事件基础

// 创建定时器事件,1000ms 后触发
ev = event_new(base, -1, EV_TIMEOUT, on_timeout, NULL);
struct timeval tv = {1, 0}; // 1秒
event_add(ev, &tv); // 将定时器事件添加到事件循环

event_base_dispatch(base); // 启动事件循环

event_free(ev); // 清理资源
event_base_free(base); // 清理事件基础
return 0;
}

2.4 信号事件

libevent 允许你注册信号处理器,以便在接收到特定信号时触发相应的回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <event.h>
#include <stdio.h>
#include <signal.h>

void on_signal(int sig, short event, void *arg) {
printf("Signal %d received\n", sig);
}

int main() {
struct event_base *base;
struct event *ev;

base = event_base_new(); // 创建事件基础

// 注册处理 SIGINT 信号的事件
ev = evsignal_new(base, SIGINT, on_signal, NULL);
event_add(ev, NULL); // 添加事件

event_base_dispatch(base); // 启动事件循环

event_free(ev); // 清理资源
event_base_free(base); // 清理事件基础
return 0;
}

3. 支持的事件通知机制

libevent 支持多个底层事件通知机制,可以根据系统的能力选择最合适的方式来实现事件通知。这些机制包括:

  • select:适用于所有操作系统的传统事件通知机制,但在高并发下性能较差。
  • poll:比 select 更高效,适用于大多数现代操作系统。
  • epoll:Linux 上的高效事件通知机制,适用于高并发场景。
  • kqueue:适用于 macOS 和 BSD 系统的事件通知机制。
  • **IOCP (I/O Completion Ports)**:Windows 上的高效事件通知机制。

libevent 会根据平台自动选择最佳的事件通知机制。

4. 线程支持

libevent 默认情况下是单线程的,事件循环在一个线程中运行。然而,它也支持多线程,可以将事件分发到不同的线程中去处理。libevent 可以将事件轮询工作分配给多个线程,从而提高并发性能。

5. 应用场景

libevent 被广泛应用于需要高性能网络通信、文件 I/O 或信号处理的应用程序中。常见的应用场景包括:

  • 高并发的网络服务器:例如 HTTP 服务器、聊天服务器、游戏服务器等。
  • 异步 I/O 程序:需要高效、非阻塞地处理大量文件操作或网络请求。
  • 定时任务调度:需要精确控制时间和定时任务的执行。
  • 跨平台高性能应用:需要在不同平台上运行的高并发应用。

6. 与其他库的对比

  • **libevent vs libuv**:

    • libeventlibuv 都实现了事件驱动的 I/O 模型,支持异步 I/O 操作,但 libevent 更注重事件的灵活性和兼容性,适用于多种操作系统和不同类型的事件源。
    • libuv 更专注于 Node.js 环境,因此它提供了更为复杂的功能,如线程池、DNS 解析等。
  • **libevent vs select / poll**:

    • libevent 是在 selectpoll 等传统 I/O 模型之上构建的,它提供了更为高级和抽象的接口,使得开发者可以更容易地实现事件驱动的程序。
    • 相比之下,selectpoll 的编程接口较为低级且复杂。

7. 安装与使用

安装(Linux)

1
sudo apt-get install libevent-dev

编译(Linux)

1
gcc -o my_program my_program.c -levent

8. 总结

libevent 是一个高效的事件通知库,适用于需要异步 I/O、定时器和信号处理的应用程序。它提供了简洁的 API 并支持多种事件通知机制,能够帮助开发者实现高效的并发程序。通过利用 libevent,开发者可以避免阻塞和线程管理的复杂性,集中精力处理业务逻辑。

event2/event.h

struct event_base

  • 用来保存Libevent分派循环的信息和状态。它是Libevent的核心,每一个应用程序都有一个event_base。它持续追踪着所有挂起和活跃的事件,并且将活跃的事件通知给你的应用。
  • 它是一个不透明的结构体,通过 event_base_new() 或者 event_base_new_with_config() 申请,通过 event_base_free() 释放。

struct event

  • 它是表示单个事件的结构体。

  • 事件可以表示一些基本条件:一个套接字变成可读,可写,可读可写,接收到的信号。

  • 通常来说,你可以通过 event_new() 创建一个事件,然后通过 event_add() 使其挂起。当 event_base 在运行时,会调用那些条件被触发的事件的回调函数。当你不需要event时,可以通过 event_free() 释放。

  • 一个事件可能处于 挂起状态,是指我们正在等待该事件的条件被触发

  • 一个事件可能处于 活跃状态,是指条件已经被触发,回调函数即将运行的事件。

  • 或者两个状态都不处于。

  • 通过 event_assign() 或 event_new() 产生的事件,既不处于活跃状态,也不处于挂起状态。

  • 通过 event_add() 使事件处于挂起状态,当这样做的时候,也可以为该事件设置一个超时时间。

  • 在 event_base_loop() 调用期间,当事件的条件被触发,或者超时时间已过,该事件的状态会变成 活跃状态。

  • 你可以通过 event_activate() 手动激活一个事件。

  • event_base 循环会调用处于活跃状态的事件的回调函数,当回调函数执行完毕,event_base 会将这些事件标记为非活跃状态(挂起)。

  • 将事件传递给 event_del(),可以使该事件变为 非挂起事件。这也会使该事件变为 非活跃事件。

  • 事件可以是 持久的 和 非持久的。非持久的事件一旦被触发就会变成非挂起事件。因此,每次调用 event_add() 最多只会运行一次。

  • 持久化的事件即使变成活跃状态也会保持挂起状态。需要手动调用 event_del(),让它不再挂起。

  • 当一个具有超时的持久化事件变为活跃状态时,它的超时会被重置。这意味着可以使用持久事件来实现周期性超时。

  • 这应该被视为不透明的结构体。你永远不应该直接读或者写它的任何字段。

  • 为了兼容旧代码,它定义在了 event2/event_struct.h 头文件中。包含此头文件可能会使代码与其他版本的 libevent 不兼容。

  • 与之相关的函数

    • event_new()
    • event_free()
    • event_assign()
    • event_get_assignment()
    • event_add()
    • event_del()
    • event_activate()
    • event_pending()
    • event_get_fd()
    • event_get_base()
    • event_get_events()
    • event_get_callback()
    • event_get_callback_arg()
    • event_priority_set()

struct event_config

  • event_base的配置
  • 有许多选项可以改变event_base的行为和实现
  • 为了避免传递这些所有的参数时导致有很复杂的构造函数,我们提供了一个抽象的数据类型,在 event_base_new_with_config() 函数中要传递它,用来设置配置信息。
  • 与之相关的函数
    • event_config_new()
    • event_config_free()
    • event_base_new_with_config()
    • event_config_avoid_method()
    • event_config_require_features()
    • event_config_set_flag()
    • event_config_set_num_cpus_hint()

void event_enable_debug_mode(void)

  • 在Libevent中启用一些通常会关闭的相对昂贵的调试检查。一般来说,这些检查会导致原本会莫名其妙的崩溃的代码在断言失败之前就失败了。需要注意的是,这个方法必须在任何事件或event_base被创建之前调用。
  • 调试模式能够捕获一下错误
    • 添加一个被重复注册的事件
    • 任何调用非注册事件的函数
  • 与之相关的函数
    • event_debug_unassign()

void event_debug_unassign(struct event *)

  • 当打开调试模式时,通知Livevent事件不再被认为是指定的,没有打开调试模式时,什么都不做。
  • 这个函数只能在未添加的事件上调用

struct event_base *event_base_new(void)

  • 创建并返回一个新的event_base,与Libeven的其余部分一起使用。
  • 成功,返回一个新的event_base;失败,返回NULL
  • 与之相关的函数
    • event_base_free()
    • event_base_new_with_config()

int event_reinit(struct event_base *base)

  • 在fork之后重新初始化 event_base
  • 有些事件机制不能在fork中存在。event base 需要用 event_reinit() 函数重新初始化。
  • 成功,返回0;失败,返回-1
  • 与之相关的函数
    • event_base_new()

int event_base_dispatch(struct event_base *base)

  • 事件分发循环
  • 这个循环会运行 event base,直到没有任何挂起,或者活跃,或者有什么调用了 event_base_loopbreak() 或者 event_base_loopexit().
  • 成功,返回0;如果有错误产生,返回-1;如果因为没有活跃或挂起的事件而退出,返回1.

const char *event_base_get_method(const struct event_base *eb)

  • 获取Libevent使用的内核事件通知机制。
  • 返回一个标识内核事件机制的字符串(kqueue, epoll, win32, etc..)

const char *event_base_get_signal_method(const struct event_base *eb)

  • 获取Libevent使用的信号处理机制
  • 返回一个标识内核事件机制的字符串,signal 是传统UNIX信号处理,kqueue_signal 是 *BSD和macOS平台的kqueue(2)-based。signalfd_signal用于仅Linux方法。

const char **event_get_supported_methods(void)

  • 获取Libevent支持的所有事件通知机制
  • 该函数按照Libevent首选的顺序返回事件机制。请注意,此列表将包括Libevent编译支持的所有后端,而不必检查操作系统是否具有所需的资源。
  • 成功,返回一个数组,其中包含指向支持方法名称的指针。数组的末尾为NULL;失败,返回NULL

int event_gettime_monotonic(struct event_base *base, struct timeval *tp)

  • 从定时器查询 event_base 当前的单调时间(单次调用时间)

event type flag

  • 需要传递给 event_base_get_num_events()的标志位,用于指定我们希望汇总计数的事件种类。
  • EVENT_BASE_COUNT_ACTIVE:统计已经被触发的活跃事件的数量
  • EVENT_BASE_COUNT_VIRTUAL:统计虚拟事件的数量,这些虚拟事件被用来表示一种内部条件,而不是一个挂起事件,该内部条件使得循环不会退出。
  • EVENT_BASE_COUNT_ADDED:统计已经被添加到 event_base 中的事件数量,包括内部事件。

int event_base_get_num_events(struct event_base *eb, unsigned int flags)

  • 获取event_base中使用标识指定的事件的数量
  • 由于event_base 添加了一些内部事件来实现某些功能,EVENT_BASE_COUNT_ADDED返回的事件数可能比 event_add() 添加的事件数要多。
  • 如果你将 EVENT_BASE_COUNT_ACTIVE 和 EVENT_BASE_COUNT_ADDED 一起传递,一个活跃事件将被计数两次。
  • 返回指定标志事件的数量。

int event_base_get_max_events(struct event_base *eb, unsigned int flags, int clear)

  • 获取在给定 event_base 中指定标识事件的最大数量。
  • 返回指定标识事件的数量

struct event_config *event_config_new(void)

  • 申请一个新的 事件配置对象
  • 这个事件配置对象可用于改变event_base的行为。
  • 成功,返回一个 用于存储配置信息的 event_config 对象;失败,返回NULL

void event_config_free(struct event_config *cfg)

  • 释放与事件配置对象关联的所有内存

int event_config_avoid_method(struct event_config *cfg, const char *method)

  • 输入一个应该避免配置的事件方法。
  • 这可用于避免不支持某些文件描述符类型的事件机制,或用于避免某些事件机制。
  • 一个应用可以使用多个 event_base 来适应不兼容的文件描述符类型。
  • 成功,返回0;失败,返回-1

enum event_method_feature

  • 用于描述 event_base 必须提供哪些功能的标志。
  • 由于操作系统的限制,不是每一个Libevent后端都支持所有可能的功能。
  • 你可以在event_config_require_features()中使用这种类型,告诉Libevent仅当你的event_base实现了给定的功能时才继续处理,并且你可以从event_base_get_features()中接收这种类型,以查看哪些功能是可用的。

enum event_base_config_flag

  • 用于 event_config_set_flag() 的标志
  • 这些标志能够改变一个已分配的 event_base的行为。
  • 与之相关函数
    • event_config_set_flag()
    • event_base_new_with_config()
    • event_method_feature

int event_base_get_features(const struct event_base *base)

  • 返回由 event_base 实现的功能的位掩码
  • 这将是按位或event_method_feature的一个或多个值

int event_config_require_features(struct event_config *cfg, int feature)

  • 输入应用程序所需要的事件方法特性。
  • 不是所有的特性或特性的组合在每个平台都支持的。代码需要准备处理 event_base_new_with_config() 返回空的情况。
  • 成功,返回0;失败,返回-1.

int event_config_set_flag(struct event_config *cfg, int flag)

  • 设置一个或多个标志,配置最终event_base的哪些部分将被初始化,以及它们将如何工作。
  • 与之相关的函数
    • event_base_config_flags
    • event_base_new_with_config()

int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)

  • 记录系统中cpu数量的提示。这用于调优线程池等,以获得最佳性能。在Libevent 2.0版本中,它仅在 Windows,IOCP中使用。
  • 成功,返回0;失败,返回-1

int event_config_set_max_dispatch_interval(struct event_config *cfg, const struct timeval *max_interval, int max_callbacks, int min_priority)

  • 记录一个间隔和/或一些回调函数,之后 event base 将检查新的事件。默认情况下,在检查新事件之前,event base 将运行与最高激活优先级激活的事件数量相同的事件。如果通过设置max_interval来配置它,它将在每次回调之后检查时间,并且在检查新事件之前不允许超过max_interval。如果通过将max_callbacks设置为>= 0来配置它,那么在检查新事件之前,它将不会运行超过max_callbacks的回调函数。
  • 这个选项可以减少高优先级事件的延迟,并避免优先级反转,即多个低优先级事件导致无法轮询高优先级事件,但会以略微降低吞吐量为代价。请谨慎使用!
  • 成功,返回0;失败,返回-1.

struct event_base *event_base_new_with_config(const struct event_config *cfg)

  • 初始化事件API
  • 使用 event_base_new_with_config() 按照指定的配置 初始化一个新的 event base。配置对象当前可用于避免某些事件通知机制。
  • 成功,返回一个能够用于注册事件的,已初始化的event_base;失败,返回NULL
  • 与之相关的函数
    • event_base_new()
    • event_base_free()
    • event_init()
    • event_assign()

void event_base_free(struct event_base *eb)

  • 释放所有与event base 相关的内存
  • 注意,这个函数不会关闭任何fd,也不会释放作为callback参数传递给event_new的内存。
  • 如果有任何待处理的终结器回调函数,这个函数会调用它们

void event_base_free_nofinalize(struct event_base *)

  • 和event_base_free类似,但是不会运行终结器

Log severities

  • EVENT_LOG_DEBUG
  • EVENT_LOG_MSG
  • EVENT_LOG_WARN
  • EVENT_LOG_ERR

typedef void (*event_log_cb)(int severity, const char *msg)

  • 一个回调函数,用于拦截Libevent的日志消息。

void event_set_log_callback(event_log_cb cb)

  • 重定向Libevent的日志消息
  • 你提供的函数不能调用任何其他libevent功能。这样做可能会产生未定义的行为。

typedef void (*event_fatal_cb)(int err)

  • 当Libevent遇到致命的内部错误时调用的函数。

void event_set_fatal_callback(event_fatal_cb)

  • 在发生致命内部错误时,重写Libevent的行为。
  • 默认情况下,如果编程错误导致无法继续正确操作,Libevent将调用exit(1)。这个函数允许你提供另一个回调函数。请注意,如果调用该函数,则程序或Libevent有问题:任何后续对Libevent的调用都可能导致未定义的行为。
  • Libevent(几乎)总是在调用该函数之前记录EVENT_LOG_ERR消息;查看最后一条日志消息,了解Libevent为什么会死亡。

void event_enable_debug_logging(ev_uint32_t which)

  • 打开调试日志,发送到默认日志处理器
  • 这是一个全局设置,如果你要调用它,必须确保在调用之前event_base是创建好的。你需要在任何多线程使用event_base之前调用它。

int event_base_set(struct event_base *eb, struct event *ev)

  • 将一个不同的event_base 与一个事件绑定。
  • 被绑定的事件不能处于活跃或挂起状态。
  • 成功,返回0;失败,返回-1

Loop flags

  • 这些标志控制着 event_base_loop() 的行为。
  • EVLOOP_ONCE:阻塞直到有一个活动事件,然后在所有活动事件的回调函数运行完毕后退出。
  • EVLOOP_NONBLOCK:不阻塞,看看哪些事件现在已经准备好了,运行优先级最高的回调函数,然后退出
  • EVLOOP_NO_EXIT_NO_EMPTY:不要退出循环,因为没有挂起的事件。相反,继续运行,直到event_base_loopexit()或event_base_loopbreak()让我们停止

int event_base_loop(struct event_base *eb, int flags)

  • 等待事件变为活跃状态,然后调用他们的回调函数
  • 这是 event_base_dispatch() 更灵活的版本
  • 默认情况下,这个循环将运行 event base,直到没有其他的挂起或活跃事件,或者直到调用了 event_base_loopbreak(),event_base_loopexit()。你可以通过参数flags覆盖它的行为。
  • 成功,返回0;有错误产生返回-1;没有活跃或挂起的事件返回1.
  • 与之相关的函数
    • event_base_loopexit()
    • event_base_dispatch()
    • EVLOOP_ONCE
    • EVLOOP_NONBLOCK

int event_base_loopexit(struct event_base *eb,const struct timeval *tv)

  • 在指定时间后退出事件循环。
  • 给定定时器到期后的下一个event_base_loop()迭代将正常完成(处理所有排队的事件),然后退出,不会再次阻塞事件。
  • 后续对event_base_loop()的调用将正常进行。
  • 成功,返回0;有错误产生,返回-1
  • 与之相关的函数
    • event_base_loopbreak()

int event_base_loopbreak(struct event_base *eb)

  • 立即中止活动的event_base_loop()。
  • Event_base_loop()将在下一个事件完成后中止循环;Event_base_loopbreak()通常在这个事件的回调函数中调用。这种行为类似于“break;”语句。
  • 后续对event_base_loop()的调用将正常进行。
  • 成功,返回0;有错误产生,返回-1
  • 与之相关的函数
    • event_base_loopexit()

int event_base_loopcontinue(struct event_base *eb)

  • 告诉正在运行的 event_base_loop() 立即扫描新的事件
  • 调用这个函数会让当前活动的event_base_loop()在当前事件回调函数结束后再次开始循环(扫描新的事件)。如果事件循环没有运行,这个函数没有作用。
  • Event_base_loopbreak()通常在这个事件的回调函数中调用。这种行为类似于“continue;”语句。
  • 后续对event_base_loop()的调用将正常进行。
  • 成功,返回0;有错误产生,返回-1
  • 与之相关的函数
    • event_base_loopbreak()

int event_base_got_exit(struct event_base *eb)

  • 就这个事件循环是否通过event_base_loopexit()收到了退出指令。
  • 当调用了 event_loopexit(),这个函数会返回true,直到进入下一个循环。
  • 如果event_base_loopexit()被调用了,返回true;否则,返回0
  • 与之相关的函数
    • event_base_loopexit()
    • event_base_got_break()

int event_base_got_break(struct event_base *eb)

  • 检查event_base_loopbreak()是否通知事件循环立即中止。
  • 如果event_base_loopbreak()被调用了,返回true;否则,返回0
  • 与之相关的函数
    • event_base_loopexit()
    • event_base_got_break()

event flags

  • 要传递给event_new()、event_assign()、event_pending()以及任何参数形式为“短事件”的参数的标志
  • EV_TIMEOUT: 表示超时。没有必要将这个标志传递给event_for new()/event_assign()来获得超时时间。
  • EV_READ: 等待一个套接字或文件描述符变为可读的
  • EV_WRITE:等待一个套接字或文件描述符变为可写的。
  • EV_SIGNAL:等到一个POSIX信号到达
  • EV_PERSIST: 持久事件:激活时不会自动移除。在激活具有超时的持久事件时,其超时时间重置为0。
  • EV_ET: 如果后端支持,选择边缘触发行为。
  • EV_FINALIZE:如果提供了这个选项,那么event_del()在等待另一个线程的事件回调完成时,不会在一个线程中阻塞。为了安全地使用这个选项,你可能需要使用event_finalize()或event_free_finalize(),以便在多线程应用程序中安全地销毁事件。更多信息请参阅这些函数。
  • EV_CLOSED: 检测连接关闭事件。您可以使用它来检测连接何时关闭,而不必从连接中读取所有挂起的数据。并非所有后端都支持EV_CLOSED。要检测或需要它,请使用特性标志EV_FEATURE_EARLY_CLOSE。

typedef void (*event_callback_fn)(evutil_socket_t, short, void *)

  • 事件的回调函数,接受三个参数。
  • 与之相关的函数
    • event_new()

void *event_self_cbarg(void)

  • 返回一个值,用于指定必须将事件本身用作回调参数。

struct event *event_new(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg)

  • 分配一个待添加的新事件结构。
  • 这个event_new() 函数返回的新事件可以在调用 event_add()和event_del()函数时使用。fd和events参数是触发事件的条件;回调函数和回调参数是告诉Libevent当事件变为活跃状态时应该做的动作。
  • 成功,返回一个必须由event_free()释放的事件结构体对象;有错误产生,返回NULL
  • 与之相关的函数
    • event_free()
    • event_add()
    • event_del()
    • event_assign()

int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg)

  • 准备一个新的、已经分配的事件结构,以便添加。
  • event_assign()函数准备一个事件结构体对象用于在未来调用event_add()和event_del()时使用。与event_new()不同的是,他不申请任何内存,它需要的是已经申请好的事件结构体对象。这样做通常会使您的代码依赖于事件结构的大小,从而与Libevent的未来版本不兼容。
  • 成功,返回0;无效参数,返回-1
  • 与之相关的函数
    • event_new()
    • event_add()
    • event_del()
    • event_base_once()
    • event_get_struct_event_size()

void event_free(struct event *)

  • 释放一个由event_new()申请的事件结构体对象。
  • 如果该事件处于挂起或活跃状态,这个函数先使它处于非挂起或非活跃状态。

typedef void (*event_finalize_callback_fn)(struct event *, void *)

  • 用于 event_finalize()和event_free_finalize()的回调函数类型。

int event_base_once(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *arg, const struct timeval *timeout)

  • 安排一次性的活动
  • 这个event_base_once()与event_new()相似。然而,它安排回调函数只被调用一次,并且不要求调用者准备事件结构。
  • 成功,返回0;有错误产生,返回-1

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

  • 向挂起事件集合中添加一个事件。
  • 成功,返回0;有错误产生,返回-1
  • 与之相关的函数
    • event_del()
    • event_assign()
    • event_new()

int event_remove_timer(struct event *ev)

  • 从挂起事件中移除定时器,但不移除事件本身。
  • 如果事件有预定的超时时间,则此函数取消该事件的计划,但将事件留在待定状态。
  • 成功,返回0;有错误产生,返回-1

int event_del(struct event *ev)

  • 从监视事件集中删除事件。
  • 函数event_del()将取消参数ev中的事件。如果事件已经被执行或者从未被添加,那么调用将不会有任何效果
  • 成功,返回0;有错误产生,返回-1
  • 与之相关的函数
    • event_add()

int event_del_nonblobk(struct event *ev)

  • 当事件的回调函数在另一个线程中运行时,即使事件是在没有EV_FINALIZE标志的情况下构造的,也不会阻塞。

int event_del_blobk(struct event *ev)

  • 当事件的回调函数在另一个线程中运行时,即使事件是用EV_FINALIZE标志构造的,也总是会阻塞。

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

  • 激活一个事件。
  • 你可以在挂起或非挂起事件上使用这个函数,使其成为活动事件,这样它的回调函数就会通过event_base_dispatch()或event_base_loop()运行。
  • 多线程程序中一个常见的用法是从另一个线程中唤醒运行event_base_loop()的线程。

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

  • 检查特定事件是否正在等待或计划中。
  • 如果事件正在等待what中的任何事件(也就是说,它已经被添加),则为True;如果事件没有被添加,则为0。

struct event *event_base_get_running_event(struct event_base *base)

  • 如果在事件的回调函数中调用,则返回该事件。
  • 当从事件的回调函数外部调用时,该函数的行为没有定义。

int event_initialized(const struct event *ev)

  • 测试事件结构是否可以初始化。
  • event_initialized()函数可用于检查事件是否已经初始化.
  • 警告:此函数仅用于区分已清空的内存块和已初始化的事件,它很容易与未初始化的内存混淆。因此,它只能用于区分初始化事件和零事件。
  • 1表示该结构可以初始化,0表示尚未初始化

evutil_socket_t event_get_fd(const struct event *ev)

  • 获取事件的套接字或信号,如果事件没有套接字,返回-1

struct event_base *event_get_base(const struct event *ev)

  • 获取与事件绑定的 event_base

event_callback_fn event_get_callback(const struct event *ev)

  • 获取与事件绑定的回调函数

void* event_get_callback_arg(const struct event* ev)

  • 获取与事件绑定的回调函数的参数

int event_get_priority(const struct event *ev)

  • 获取事件的优先级
  • 与之相关的函数
    • event_priority_init()
    • event_get_priority()

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

  • 提取用于构造给定事件的所有参数。
  • event_base被复制到base_out, fd被复制到fd_out,以此类推
  • 如果任何一个“_out”参数为NULL,它将被忽略。

size_t event_get_struct_event_size(void)

  • 返回编译Libevent库时使用的struct event的大小

const char *event_get_version(void)

  • 获取Libevent的版本

event_get_vision_number()

  • 获取Libevent版本号

int event_base_priority_init(struct event_base *eb, int npriorities)

  • 设置不同事件优先级的个数
  • 默认情况下,Libevent给所有活跃事件设置相同的优先级。然后,在某些情况下需要使用更高的优先级优先处理某些事件。
  • 成功,返回0;有错误产生,返回-1
  • 与之相关的函数
    • event_priority_set()

int event_base_get_npriorities(struct event_base *eb)

  • 获取不同事件优先级的数量。

int event_priority_set(struct event *ev, int priority)

  • 为一个事件设置优先级
  • 成功,返回0;有错误产生,返回-1

const struct timeval *event_base_init_common_timeout(struct event_base *base, const struct timeval *duration)

  • 准备一个event_base,以使用相同时间的大量超时

void event_base_dump_events(struct event_base *base, FILE *output)

  • 将所有插入和/或活动事件的可读描述写入提供的stdio流。
  • 这是为了调试。它的格式不能保证在libevent版本之间是相同的。

void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events)

  • 激活给定fd和事件掩码的所有挂起事件。

void event_base_active_by_signal(struct event_base *base, int sig)

  • 激活给定信号编号的所有挂起信号
  • 该函数只激活挂起事件。未添加的事件不会变为活动状态。

typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *)

  • 通过event_base_foreach_event在事件基中迭代事件的回调

int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb, fn, void *arg)

  • 在事件循环中遍历所有添加或活动的事件,并对每个事件调用给定的回调函数。

int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv)

  • tv设置为当前时间(由gettimeofday()返回),如果可能,查看base中缓存的值,如果没有缓存的时间,则适当调用gettimeofday()或clock_gettime()。
  • 成功,返回0;失败,返回负值

int event_base_update_cache_time(struct event_base *base)

  • base中的cached_tv更新为当前时间
  • 成功,返回0;失败,返回-1

void libevent_global_shutdown(void)

  • 释放所有由Libevent分配的全局资源。
  • 该函数不会释放开发人员控制的资源,如event_bases、events、bufferevents、listeners等。它只释放像全局锁这样没有其他释放方式的资源。
  • 实际上没有必要在退出前调用这个函数:它释放的每一个资源都会在退出时被释放。它的存在主要是为了使资源泄漏调试工具不会将Libevent视为在退出时持有资源。
  • 只有在不调用其他Libevent函数时,才应该调用此函数——例如,当干净地退出程序时。
感谢老板支持!敬礼(^^ゞ