Nginx源码分析—业务流程

到此为止,我们假设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监听的对象

时间: 2024-11-25 07:22:44

Nginx源码分析—业务流程的相关文章

nginx源码分析--进程间通信机制 & 同步机制

Nginx源码分析-进程间通信机制 从nginx的进程模型可以知道,master进程和worker进程需要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号,master进程主要就是监控.接受外部信号,将有必要的信号传递给worker进程,master进程大部分时间都是阻塞在sigsuspend()函数调用上.Worker进程屏蔽了所有的外部信号,那么Master进程就通过套接字和worker进程通信,worker进程修改全局变量,使得worker进程接受

nginx源码分析--nginx模块解析

nginx的模块非常之多,可以认为所有代码都是以模块的形式组织,这包括核心模块和功能模块,针对不同的应用场合,并非所有的功能模块都要被用到,附录A给出的是默认configure(即简单的http服务器应用)下被连接的模块,这里虽说是模块连接,但nginx不会像apache或lighttpd那样在编译时生成so动态库而在程序执行时再进行动态加载,nginx模块源文件会在生成nginx时就直接被编译到其二进制执行文件中,所以如果要选用不同的功能模块,必须对nginx做重新配置和编译.对于功能模块的选

nginx源码分析--模块分类

ngx-modules Nginx 主要的模块大致可以分为四类: handler – 协同完成客户端请求的处理.产生响应数据.比如模块, ngx_http_rewrite_module, ngx_http_log_module, ngx_http_static_module. filter – 对 handler 产生的响应数据做各种过滤处理.比如模块, ngx_http_not_modified_filter_module, ngx_http_header_filter_module. ups

nginx源码分析--ngx_http_optimize_servers()函数

这个函数做了连部分工作:1)以端口为入口点 将有用的信息存放到hash表内 2)调用ngx_http_init_listening()函数 对端口进行监听 1. 在ngx_http_core_main_conf_t结构体中有一个字段为ports,是一个数组,数组内存放的全是ngx_http_conf_port_t:对于每一个端口信息(ngx_http_conf_port_t),调用 ngx_http_server_names函数,同时也调用ngx_http_init_listening函数,这里

nginx源码分析--从源码看nginx框架总结

nginx源码总结: 1)代码中没有特别绕特别别扭的编码实现,从变量的定义调用函数的实现封装,都非常恰当,比如从函数命名或者变量命名就可以看出来定义的大体意义,函数的基本功能,再好的架构实现在编码习惯差的人实现也会黯然失色,如果透彻理解代码的实现,领悟架构的设计初衷,觉得每块代码就想经过耐心雕琢一样,不仅仅实现了基本的功能给你,为其他人阅读也会提供很好的支持.细致恰当的命名规则就可以看出作者的功力. 2)更好更高的软件性能体现在架构设计上,好的架构会让软件更加稳定.容易维护.便于扩展.从核心模块

nginx源码分析--nginx外部信号 命令参数

nginx命令行参数 不像许多其他软件系统,Nginx 仅有几个命令行参数,完全通过配置文件来配置 -c </path/to/config> 为 Nginx 指定一个配置文件,来代替缺省的. -t 不运行,而仅仅测试配置文件.nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件. -v 显示 nginx 的版本. -V 显示 nginx 的版本,编译器版本和配置参数. nginx控制信号 可以使用信号系统来控制主进程.默认,nginx 将其主进程的 pid 写入到 /u

nginx源码分析--监听套接字的创建 套接字的监听 HTTP请求创建连接

作为一个web服务器,那么肯定是有监听套接字的,这个监听套接字是用于接收HTTP请求的,这个监听套接字的创建是根据配置文件的内容来创建的,在nginx.conf文件中有多少个地址就需要创建多少个监听套接字.这里不说各个结构体的构造 只说大体情况! 1).首先在main函数中调用了ngx_init_cycle()函数,在这个函数的最后调用了ngx_open_listening_sockets函数,这个函数负责将创建的监听套接字进行套接字选项的设置(比如非阻塞.接受发送的缓冲区.绑定.监听处理) 2

nginx源码分析--配置信息的继承&amp;合并

这里只讲述http{}模块下的配置: 在ngx_http_block()函数内(这个函数别调用时在ngx_inti_cycle内的ngx_conf_parse函数,这个函数遇到http命令时 回调ngx_http_block,开启http{}配置块的解读工作),针对每一个http模块,调用init_conf之后,有调用了ngx_http_merge_servers().这是为何! 首先明确几点:一个http{}配置块内可以包含多个server{}配置块,每个server{}配置块可以包含多个lo

Nginx源码分析:3张图看懂启动及进程工作原理

编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由陈科在高可用架构群分享.转载请注明来自高可用架构公众号「ArchNotes」.   导读:很多工程师及架构师都希望了解及掌握高性能服务器开发,阅读优秀源代码是一种有效的方式,nginx 是业界知名的高性能 Web 服务器实现,如何有效的阅读及理解 nginx?本文用图解的方式帮助大家来更好的阅读及理解 nginx 关键环节的实现.   陈科,十年行业从业经验,曾在浙江电信.阿里巴巴.华为.五八同城任开发工程及架构师等职,目前负责河狸