到此为止,我们假设ngx_init_cycle已经结束,我们暂时不管他做了什么,我们从他做的效果进入。
从常理上来讲,如果一个请求到达,那么我们需要接受这个请求,那么就从请求来介绍!
在ngx_event_process_init函数中将监听套接字上的读事件注册为ngx_event_accept,ngx_event_accept是为了接受请求的,它负责接收一个连接,那么连接接收完成以后直接调用这个监听套接字上的处理函数ls->handler(c);那么这个时候是怎么处理的呢?他是如何被赋值的呢?
这就需要ngx_init_cycle中的已经调用过的函数,ngx_http_block(其实ngx_event_process_init也是在ngx_init_cycle解析配置文件事被调用的)。Ngx_http_block函数内容很丰富,解析配置,初始化一些东西,到了最后:ngx_http_optimize_servers
ngx_http_optimize_servers这个就是进入一些回调的注册ngx_http_init_listening,从函数的名字是为了初始化监听套接字。
ngx_http_add_listening函数是创建一个监听套接字,并对这个监听套接字进行初始化。这个监听套接字(ngx_listening_t类型)上的handler被赋值为ngx_http_init_connection
ngx_http_init_connection函数初始化一个连接,接受完以后就是调用这个来初始化一个连接,同时将这个连接上的读写时间的回调赋值
rev = c->read;
rev->handler = ngx_http_wait_request_handler;//连接上读事件回调
c->write->handler = ngx_http_empty_handler;//连接上的写事件的回调 这个为空,在开始只有读事件。
ngx_http_wait_request_handler函数整将创建一个请求结构体,c->data = ngx_http_create_request(c);
同时rev->handler = ngx_http_process_request_line; //将读事件赋值为此并直接调用此函数
ngx_http_process_request_line(rev);
ngx_http_process_request_line(rev)中需要ngx_http_parse_request_line解析请求行,如果没有解析成功,说明请求行还没有读完,所以读事件上的回调还是这个,如果解析成功,
rev->handler = ngx_http_process_request_headers;//读事件上的回调为请求头
ngx_http_process_request_headers(rev);
ngx_http_process_request_headers(rev);函数中也是一个死循环,直到读取头部信息完整才结束,读取结束以后就解析ngx_http_parse_header_line,解析头部信息,解析完成以后就处理头信息ngx_http_parse_header_line,处理结束就ngx_http_process_request,处理请求。
ngx_http_process_request,这个函数进入了http请求中的11个阶段,这个nginx为Http请求来设计的
c->read->handler = ngx_http_request_handler;
c->write->handler = ngx_http_request_handler;
r->read_event_handler = ngx_http_block_reading;
ngx_http_handler(r);
ngx_http_run_posted_requests(c);
这几个函数都很重要。连接上的读写事件都是ngx_http_request_handler,然而请求上的读事件回调为ngx_http_block_reading。首先说下流程
ngx_http_request_handler函数中就是根据发生了读写事件中的哪个,转而调用了该请求上记录的write_event_handler或者read_event_handler。接下来调用ngx_http_run_posted_requests.
在ngx_http_handler函数中将请求上的写回调write_event_handler记录为ngx_http_core_run_phases,接下来就是调用ngx_http_core_run_phases这个函数,
ngx_http_core_run_phases这个函数就是进入了11个阶段。刚开始感觉非常奇怪。
到此为止,HTTP请求流程结束。
至于ngx_http_run_posted_requests函数,是因为这个请求上可能有多个子请求,子请求直接使用请求上的write_event_handler函数处理
有几点需要讲解一下;
Epoll模型监控的是读写事件,是ngx_event_t结构体,是一个连接(ngx_connection_t结构体)中的ngx_event_t对象,也即是ngx_connectin_t中的read&write字段。
在ngx_http_request_handler函数中将读写事件进行了转移,转移到了请求中的read_event_handler和write_event_handler回调。
请求中的read_event_handler和write_event_handler函数存在的原因是什么呢?
为了请求的转移,每一个请求都需要记住自己走到了哪个步骤,而不是epoll中注册的读写事件回调,Nginx需要全程非阻塞,自己处理到某个阶段需要自己记录,等到自己再进行处理,就可以接着处理了也即是从接收到一个完整的请求以后,进入11个阶段的处理后,处理的流程需要请求自己掌控,这也是异步的思想,那么一个请求处理完一个阶段,什么时候计入下一个阶段呢,有定时器激活。
要明白一点就是,事件结构体(ngx_event_t)中的data域是ngx_connection_t结构体,
Ngx_connection_t结构体中的data域是请求结构体(ngx_http_request_t),请求中的connection对应着这个请求对应的一个连接。连接上的读写事件(ngx_event_t)是epoll监听的对象