目录
概述
Nginx中ngx_event.c主要实现以下功能
- 事件模块的初始化
- 事件的添加和删除
- 事件循环的实现
- 总结:Nginx中每一个连接都用一个单独的结构体管理起来,每个连接中又有不同的事件处理结构体。然后统一将这些连接交给epoll管理,从而实现连接的快速反应。
Nginx中ngx_event.h主要实现
- 定义不同类型
- ngx_event_s结构体,描述事件的数据结构,其中包括处理函数和状态标志
- 事件模块接口,定义不同事件驱动机制需要实现的函数接口
ngx_event.h
ngx_event_s结构体(Nginx事件处理比如读写的核心数据结构)
data
:指向与事件相关的数据,一般是指向ngx_connection_t
结构体的指针。handler
:事件处理函数,当事件触发时调用该函数。log
:指向日志对象,用于记录事件相关的日志信息。index
:事件在事件数组中的索引。
重点:事件处理函数(epoll多路转接的实现)
- 首先定义函数原型,分别有添加事件、删除事件、处理所有事件并定时
- 其次提供事件模块的接口,该接口用于不同的驱动实现,此处只重点关注epoll的实现
void ngx_event_add(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
void ngx_event_del(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
void ngx_process_events_and_timers(ngx_cycle_t *cycle);
事件机制的实现
- Linux下epoll的实现,需要上述图2中ngx_event_module_t定义的接口函数,例如增加删除一个事件
- 分析ngx_epoll_module结构体(里面是一些epoll函数的声明)
例如EPOLL添加事件函数的实现
static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) {
struct epoll_event ee;
int op;
// 设置事件类型
if (event == NGX_READ_EVENT) {
ee.events = EPOLLIN | EPOLLET;
} else if (event == NGX_WRITE_EVENT) {
ee.events = EPOLLOUT | EPOLLET;
}
// 设置事件数据
ee.data.ptr = (void *) ((uintptr_t) ev | ev->instance);
// 添加或修改事件
if (ev->active) {
op = EPOLL_CTL_MOD;
} else {
op = EPOLL_CTL_ADD;
ev->active = 1;
}
if (epoll_ctl(ep, op, ev->fd, &ee) == -1) {
return NGX_ERROR;
}
return NGX_OK;
}
ngx_event.c
初始化事件模块:选择合适数据结构+选择事件驱动机制(例如选择epoll、红黑树等)
添加事件:将一个事件添加到事件驱动机制,例如将事件放到epoll中进行管理
删除事件:将事件从epoll中移除(当然也可以从其他的事件驱动机制中删除)。从内核中移除对该事件的关心。
事件循环:调用具体事件模块的事件处理函数,同时调用定时器
- 获取下一个定时器事件的超时时间
- 调用具体的事件模块处理函数
- 更新定时器
epoll具体事件处理实现
- 调用epoll_wait 获取就绪事件:由内核返回有几个监控的事件已经准备继续
- 遍历所有就绪的事件,然后调用相应的函数对其进行处理
初始化定时器,Nginx底层使用一个红黑树管理素所有的定时器
添加定时器中的事件
- 主要作用是将一个定时器事件添加到定时器的红黑树中
- 计算定时器事件的触发事件,定时器在特定的时间内被触发
- 将定时器事件插入到定时器红黑树中
处理超时事件
- 获取当前时间
- 遍历定时器红黑树中多有的节点,找到已经超时的定时器事件
- 调用定时器事件的处理函数,即预先设定的定时器事件的处理函数
知识点补充
ngx_connection_t 结构体
该结构体主要用于表示网络连接的核心数据结构,其封装了网络连接中所需要的相关信息,即是将连接打包管理了起来。
- 结构体部分定义分析
具体使用分析
- 创建连接
- 客户端连接时,Nginx创建爱一个ngx_connection_t结构体实例,同时对结构体实例初始化
- 事件处理函数封装
- 该结构体中包含了读事件和写事件,当这些事件被触发的时候,调用相应的事件处理函数进行处理
- 发送数据
- 需要向客户端发送数据的时候,通过send函数指针发送
分析事件和连接如何关联
- ngx_event_t结构体中拥有一个指向ngx_connection_t的指针
新连接到来后,Nginx创建一个ngx_connnection_t的实例,然后在使用完成后又会关闭该连接
- 创建连接
- 释放连接