【Linux】【网络】Libevent整个的使用流程总结(与接口函数结合)
【Linux】【网络】Libevent整个的使用流程总结(与接口函数结合)
我大概画了一个图,大家将就看一下:
大概描述:以epoll为例(前面有提到)
1. 创建一个Libevent 实例–>event_base(Reactor反应器)
用户
调用 event_base_new()或者event_init()函数创建一个Libevent实例 并返回event_base* 类型的指针
内核
创建event_base 结构 (Reactor反应器)event_base里面有四个部分 分别是:
- event_io_map io —>存储注册的event事件
- void * evbase -->指向epollop结构体–>与epoll相关内容
- void * evbase–>epollop结构体—>是通过eventop里面的void*(*init)函数指针初始化的
- eventop*evsel -->指向eventop结构体–>事件多路分发器 本质上是将io复用(select,poll,epoll)接口统一实现,提供统一接口
- evcallback_list * activequeues -->存放就绪文件描述符 事件多路分发器获得的就绪文件描述符放在这里
2.事件的注册和映射
用户
调用 **event_new()和event_add()**函数注册事件 并将事件添加
内核
- 创建event 结构 (事件处理器)并将它与某个文件描述符(
fd
)相关联。 - 在 event_base中维护一个 event_io_map类型的结构。
- event_io_map是一个
哈希表
(方便查找对应的文件描述符),用于将**文件描述符和event对象映射 **。 - 每个文件描述符 fd 都会有一个对应的 event_map_entry 结构,其中包含了该文件描述符所有的事件用链表串在一起(比如EV_READ, EV_WRITE 等)(看一下上面的图)。
- 通过 event_add函数,将 event 插入到 event_base 的 event_io_map中,并将文件描述符
fd
添加到 IO 多路复用器(eventop)中。
3. 事件的触发和激活
用户
调用 event_base_dispatch()或者event_base_loop() 函数启动事件循环
内核
- Libevent 会通过event_base–>eventop–>公共接口dispatch 底层调用 event_base_loop ()
- 当事件循环运行时,Libevent 会调用相应的 IO 复用器(
epoll_wait()
)来等待文件描述符的事件。假设某个文件描述符的事件被触发,例如数据变为可读,epoll_wait
会返回相关的事件信息,这些信息会被传递到event_base–>evcallback_list * activequeues(激活队列) -->存放就绪文件描述符
4. 激活队列的处理
-
Libevent 会根据以下方式处理触发的事件:
-
通过文件描述符
fd
,event_base->event_io_map可以找到对应的 event_map_entry。这是因为在event_io_map
中,fd
被用作键值,通过哈希计算可以快速定位到与该文件描述符相关的event_map_entry
结构。 -
每个
event
对象都有一个 ev_events字段,表示该事件的类型(EV_READ 或 EV_WRITE等)。Libevent 会通过 ev_events字段,查找该事件的具体回调函数。 -
每个
event
都会通过回调函数(如evcallback
)进行处理。 -
回调函数的执行:在事件循环的后续步骤中,Libevent 会从激活队列中取出事件,并执行它们的回调函数(例如 evcallback)。每个事件的回调函数会在事件触发时被调用。
5. 关键函数和流程
-
event_add
:- 将事件添加到
event_base
中的event_io_map
里,并注册到 IO 复用器(如epoll
)。
- 将事件添加到
-
dispatch
(IO多路复用器的dispatch
):- 在事件循环中,
dispatch
被调用来启动事件的检测(例如epoll_wait
)。
- 在事件循环中,
-
激活队列:
- 当某个事件被触发时,Libevent 会将它添加到激活队列中,等待后续处理。
-
回调函数的执行:
- 从激活队列中取出事件并执行其回调函数,通常通过
evcallback
字段来调用。
- 从激活队列中取出事件并执行其回调函数,通常通过
6. 具体示例
假设我们注册一个文件描述符 fd
的 EV_READ
事件并且数据到达,Libevent 会执行以下步骤:
- 调用
event_add
将文件描述符fd
和事件类型EV_READ
添加到event_base
的event_io_map
中。 event_base_loop
启动并等待事件。epoll_wait
(作为dispatch
的一部分)监控fd
的事件,当数据可读时返回。ev_fd
找到对应的event
结构,并根据ev_events
判断是EV_READ
事件。- 将
event
添加到激活队列。 - 在后续的事件循环中,Libevent 会从激活队列中取出事件并执行回调函数。