关于ngx_listening_t
的一些记录
顺序随机
1. ngx_init_cycle() :
处理继承,申请ls存储数组的空间,
1.从旧nginx继承过来ls个数,设置新的nginx监听端口的最大个数,默认为最多10
2.申请ls的存储空间,并设置ls数组的一些性质:nelts, size, nalloc, pool
3.判断ls的一些属性是从旧nginx继承还是重新设置
如果继承,受影响的属性有:
- remain = 0:设置不保留旧的ls,等继承过来后如果原fd关掉后就全部销毁
- ignore: 根据旧的nginx_ls判断是否继承ls_fd,就是不再重新打开新的,直接拿过来用。
- 如果新旧相应ls的sockaddr一致,就继承这些属性:fd,nls.previous,nls.listen=1(该fd已监听),deferred_accep
如果重新设置:
- open = 1, accept_filter(?), deferred_accept(?)
4.打开listening_socket, ngx_open_listening_sockets()
5.配置listening_socket, ngx_configure_listening_sockets()
6.关闭不用的ls_fd
使用remain和ls.fd判断是否需要关闭
2.ngx_open_listening_sockets(ngx_cycle_t *cycle):
打开监听文件描述符,设置重用和非阻塞等基础属性
- 如果ignore==1或者fd != -1或者inherited==1就跳过,说明不需要再打开该fd(可能是需要关闭或者已经打开了的)。
- 调用
ngx_socket()
打开ls_fd - 设置端口重用:
setsocketopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuseaddr, sizeof(int))
- 不适用AIO_EVENT时设置fd为非阻塞:
ngx_nonblocking(s)
bind(s, ls[i].sockaddr, ls[i].socklen)
listen(s, ls[i].backlog)
, 后来还会重新调整backlog- 设置
ls[i].listen = 1;
- 会重试5次,每次间隔500ms
3.ngx_configure_listening_sockets(ngx_cycle_t *cycle)
配置监听文件描述符的一些附加属性
- 配置日志文件:
ls[i].log = *ls[i].logp;
- set
rcvbuf
- set
sndbuf
- set
keepalive
- 调整backlog,
- 调整deferred_accept,根据SO_ACCEPTFILTER和TCP_DEFER_ACCEPT来判断不同系统的处理方式
4.ngx_close_listening_sockets(ngx_cycle_t *cycle)
关闭ls.fd连接上的事件,关闭文件描述符
- set
ngx_accept_mutex_held = 0; ngx_use_accept_mutex = 0;
- 如果ls上的connection上的读事件还活跃,就先删除事件,再删除该连接,并置c->fd = -1
ngx_close_socket(ls[i].fd)
- ls[i].fd = -1;
- 最后,set
cycle->listening.nelts = 0
5.ngx_http_optimize_servers()
组织监听端口信息,初始化监听
- 调用
ngx_http_init_listening()
6.ngx_http_init_listening()
初始化listening
- 循环添加ls,
ngx_http_add_listening()
- 申请hport存储空间
7.ngx_http_add_listening()
设置ls的初始操作句柄
- 创建一个ls,
ngx_create_listening()
- set
ls->addr_ntop = 1;
- ***set
ls->handler = ngx_http_init_connection
, 非常重要 *** - 设置poll_size, post_accept_timeout, logp, log.data, log.handler, backlog, rcvbuf, sndbuf, keepalive, accept_filter,deferred_accept,
8.ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
创建ls的存储空间
- 向cf->cycle->listening数组中添加一个ls
- 申请ls的存储空间
- 配置该ls的地址的相关信息:
sockaddr, socklen, addr_text.len, addr_text.data, fd=-1, type = SOCK_STREAM, backlog
9.ngx_http_init_connection()
http处理框架的第一个事件返回句柄,初始化http连接
- 申请ngx_http_connection_t的存储空间(hc,代表一个address:port组合)
- set
c->data = hc
, 该c是建立tcp连接后的ngx_connection_t - 根据address:port的个数不同做不同的处理
- 配置hc的相应属性:addr_conf
- set hc->conf_ctx默认配置
- set ngx_http_log_ctx_t的相关属性,http的日志记录属性:
connection = c;request=NULL; current_request = NULL;
- set c->log的相关性质:
connection = c->number; handler = ngx_http_log_error; data = ctx; action = "waiting for request";
- set
log_error = NGX_ERROR_INFO;
- 配置读事件为
ngx_http_wait_request_handler
- 配置写事件为
ngx_http_empty_handler
- 检查是否支持SPDY或HTTP_SSL协议,需要设置对应的读事件
- 检查事件是否已经准备好了,为什么在这里就可以检查?因为是event_accept调用的http_init_connection,这时候如果是deferred accept()或者,rtsig, aio, iocp事件模型,就会暂缓调用rev->handler,也就是ngx_http_wait_request_handler,等待真正发送过来数据之后才会调用该handler,而不是发现syn过来就开始创建。
- 该事件还没准备好的时候,就把它添加到定时器的红黑树中,
- 设置该连接可重用,也就是可以再次被使用???
- 将该读事件添加到epoll框架中
10.ngx_event_process_init(ngx_cycle_t *cycle)
初始化事件驱动框架,在这里会把ls的read->handler都设置为ngx_event_accept,并添加到epoll框架中等待事情发生,发生后就会调用ls->handler,也就是在http框架初始化阶段设置的ngx_http_init_connection()函数。cycle中的一些connection被拿来用做ls的专属连接来用,而不是分配给每个worker进程全部用作http连接(????)
- 使用ls.fd新建connection,利用此connection的一些位置存储信息(在ngx_event_accept中会使用到)
- set
c->log = &ls[i].log;
- set
c->listening = &ls[i];
- set
ls[i].connection = c;
- set
c->read->rev->log = c->log;
- set
c->read->rev->accept = 1;
表示该连接用于accept - set c->read->rev->deferred_accept为ls[i]的deferred_accept
- set
c->read->rev->handler = ngx_event_accept;
非常重要 - 将c->read->rev事件添加到epoll中去处理
11.ngx_event_accept(ngx_event_t *ev)
- 判断该事件是否超时,如果超时,就重新启用该事件
ngx_enable_accept_events()
,并设置ev->timeout = 0 - 获取配置信息
- 根据使用的事件处理框架来判断ev->available,可以用来连续建立连接而不返回,以此加快建立连接的数量,尽可能多的让客户端连上来。
- 获取附在ls上的连接c的信息(在ngx_event_process_init中设置的):listening结构体和ls_fd
- set
ev->ready = 0;
- s = accept()
- 处理accept()各种错误
- set
ngx_accept_disabled
,用于负载均衡 - 用s去get新连接c
- 设置该新连接c的各种属性:申请c->pool存储空间, c->sockaddr, 申请c->log存储空间
- 设置该s为非阻塞
- 设置c->log为&ls->log
- set 该连接的读写方法
c->recv = ngx_recv;....
- set
c->pool->log = &ls->log
- set
c->socklen = socklen; c->listening = ls; c->local_sockaddr = ls->sockaddr; c->unexpected_eof = 1;
最后表示不希望没有数据,这是刚开始建立连接,当然需要读取数据 - set
c->write->ready = 1
- 如果该连接事件是延迟连接的,就把rev->ready设为1,以通知http_init_connection,该连接准备好了。因为如果设置了延迟连接,则在accept的时候就已经有数据发过来了,那样http_init_connection就可以直接进行处理了
- set
c->read->log = log; c->write->log = log;
- ngx_connection_counter+1
- 处理该连接的文本地址信息
- 如果没用epoll,可以调用ngx_add_conn把读写事件都添加到事件处理机制中
- 调用
ls->handler(c);
也就是http_init_connection来处理
12.ngx_enable_accept_events(ngx_cycle_t *cycle)
重新激活该连接事件
- 循环判断该连接事件的读事件是否活跃,if(c->read->active)
- 不活跃的就把c->read再添加到epoll中
13.ngx_master_process_cycle(ngx_cycle_t *cycle)
14.ngx_add_inkherited_sockets(ngx_cycle_t *cycle)
从环境变量中恢复旧nginx程序的监听端口,获取后会调用ngx_set_inherited_sockets()
进行相应配置,比如说
从fd获取缓冲区大小等,配置ls相应的值
15.ngx_set_inherited_sockets(ngx_cycle_t *cycle)
见14
关于listening从建立监听到处理http请求的调用链
main():nginx.c–>
ngx_init_cycle(ngx_cycle_t *old_cycle):ngx_cycle.c–>
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename):ngx_conf_file.c–>
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last):ngx_conf_file.c–>
cmd->set():ngx_conf_file.c___ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf):ngx_http.c–>
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports):ngx_http.c–>
ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port):ngx_http.c–>
ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr):ngx_http.c–>
ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen):ngx_connection.c–>
main():nginx.c–>
ngx_master_process_cycle(ngx_cycle_t *cycle):ngx_process_cycle.c–>
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type):ngx_process_cycle.c–>
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn):ngx_process.c–>
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data):ngx_process_cycle.c–>
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker):ngx_process_cycle.c–>
ngx_modules[i]->init_process(cycle):ngx_process_cycle.c___ngx_event_process_init(ngx_cycle_t *cycle):ngx_event.c–>
ls->c->read->handler==event_accept()___ngx_event_accept(ngx_connection_t *c, ngx_cycle_t *cycle):ngx_event_accept.c–>
ls->handler(c)==ngx_http_init_connection(ngx_connection_t *c):ngx_http_request.c–>
ngx_http_wait_request_handler(ngx_event_t *rev):ngx_http_request.c