首页 > 代码库 > 【Nginx】事件和连接
【Nginx】事件和连接
不同的操作系统对应不同的事件驱动机制,在Linux 2.6之后使用epoll机制,对应的事件驱动模块是ngx_epoll_module。Nginx的ngx_event_core_module模块根据操作系统确定使用哪一个事件驱动模块。事件驱动模块在ngx_module_t的ctx通用接口是ngx_event_module_t,定义如下所示:
typedef struct { ngx_str_t *name; // 事件模块名字 // 解析配置项之前调用,创建存储配置项参数的结构体 void *(*create_conf)(ngx_cycle_t *cycle); // 解析完配置项后的回调函数 char *(*init_conf)(ngx_cycle_t *cycle, void *conf); // 每个事件模块需要实现的10个抽象方法 ngx_event_actions_t actions; } ngx_event_module_t; // 事件模块通用接口
ngx_event_actions_t结构体定义如下:
// 每个事件模块需要实现的10个方法 typedef struct { // 将一个事件添加到事件驱动机制 ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); // 将一个事件从事件驱动机制中删除 ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); // 启动一个事件,目前没有调用这个方法 ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); // 禁用一个事件,目前没有调用这个方法 ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); // 将一个连接添加到事件驱动机制中,连接上的读、写事件即被加入到了事件驱动机制中 ngx_int_t (*add_conn)(ngx_connection_t *c); // 从事件驱动机制中删除一个连接的读、写事件 ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); // 暂无用 ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait); // 处理事件的方法,由处理、分发核心函数ngx_process_events_and_timers调用 ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); // 初始化事件驱动模块 ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer); // 事件驱动模块退出前调用的方法 void (*done)(ngx_cycle_t *cycle); } ngx_event_actions_t;
事件由ngx_event_t结构体定义:
typedef struct ngx_event_s ngx_event_t; // 代表事件的结构体 // 代表事件的结构体 struct ngx_event_s { ... ngx_event_handler_pt handler; // 核心,事件消费函数,定义如何处理事件 ... };
在ngx_event_t中,我们最关心handler成员,它决定了它所属的事件发生时的处理方法。
事件不需要创建,因为在Nginx启动时初始化ngx_cycle_t的过程中就分配了所有读、写事件的空间:
struct ngx_cycle_s { ... ngx_connection_t *connections; // 保存当前进程中所有的连接 ngx_event_t *read_events; // 保存所有的读事件 ngx_event_t *write_events; // 保存所有的写事件 ... };
这样,每个连接就对应了一个写事件和一个读事件。将事件添加到epoll的方法如下:
- ngx_handle_read_event:将读事件添加到事件驱动模块(epoll)中。
- ngx_handle_write_event:将写事件添加到事件驱动模块(epoll)中。
当把事件添加到epoll等事件驱动机制中后,将会发生一连串的触发事件的反应:
- 连接上出现可读/可写事件
- epoll机制捕获到这一事件后返回
- 连接所对应的读/写事件结构体中的handler函数被调用
连接的定义
在Nginx中定义了两种连接:
- ngx_connection_t:被动连接。由客户端主动发起。
- ngx_peer_connection_t:主动连接。用于主动和上游服务器进行通信。
这里只关心被动连接,被动连接的定义如下所示:
// 表示一个连接的结构体 struct ngx_connection_s { void *data; // 连接未使用时,充当next指针连接池中下一个空闲的连接,当被使用时,是具体情况而定 ngx_event_t *read; // 连接对应的读事件 ngx_event_t *write; // 连接对应的写事件 ngx_socket_t fd; // 套接字描述符 ngx_recv_pt recv; // 接收方法1 ngx_send_pt send; // 发送方法1 ngx_recv_chain_pt recv_chain; // 接收方法2 ngx_send_chain_pt send_chain; // 发送方法2 ngx_listening_t *listening; // 连接对应的监听对象 off_t sent; // 已发出去的字节数 ngx_log_t *log; ngx_pool_t *pool; // 内存池 struct sockaddr *sockaddr; // 保存网络地址 socklen_t socklen; // 网络地址长度 ngx_str_t addr_text; // 客户端IP地址 ngx_str_t proxy_protocol_addr; struct sockaddr *local_sockaddr; // 本机所监听的网络地址 socklen_t local_socklen; // 网络地址长度 ngx_buf_t *buffer; // 接收buffer ... };
当Nginx服务器接和客户端建立连接后,就会获得一个ngx_connection_t实体。和事件一样,连接不需要额外创建,它是从ngx_connection_t连接池中获得的,连接池在Nginx启动阶段就已经分配好了,由ngx_cycle_t结构体的connections成员和free_connections成员共同管理,如下图所示:
从上图可以看出,connections指向整个连接池开头,free_connections指向第一个空闲连接。获得和归还连接都是在free_connections指向的空闲链表表头进行的。注意,上图左侧的队列在物理存储上是连续存储的,也就是数组,而空闲链表是一条逻辑上的链表(通过data成员相连)用于管理空闲连接。数组的大小由配置文件中的配置项决定。上面说过,一个连接对应一个读事件和一个写事件,从上图可以看出,相同下标的连接和事件相互关联。
向连接池获取连接和归还连接到连接池的函数接口如下:
- ngx_get_connection:获取连接,也就是得到一个ngx_connection_t结构体实体。
- ngx_free_connection:归还连接。
参考:
《深入理解Nginx》 P287-P300.
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。