文档章节

Nginx源码解析- http模块分析

Foyon
 Foyon
发布于 2013/12/20 16:25
字数 1843
阅读 126
收藏 0

Nginx源码解析-
http模块分析

@author Foyon

1.Http模块整体工作原理

二、event模块工作原理

三、HTTP框架初始化

断点看源码
gdb->
->file /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx
->b ngx_http_block
->r
->p *cf
->p *cmd
->p *cf->conf_file->buffer

###############################################################

(gdb) file /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx

Reading symbols from /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx...done.

(gdb) b ngx_http_block

Breakpoint 1 at 0x43b0a6: file src/http/ngx_http.c, line 121.

(gdb) info b

Num Type Disp Enb Address What

1 breakpoint keep y 0x000000000043b0a6 in ngx_http_block at src/http/ngx_http.c:121

(gdb) r

Starting program: /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx

[Thread debugging using libthread_db enabled]

Breakpoint 1, ngx_http_block (cf=0x7fffffffe270, cmd=0x71db80, conf=0x760a38) at src/http/ngx_http.c:121

121 {

Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.x86_64 keyutils-libs-1.4-4.el6.x86_64 krb5-libs-1.10.3-10.el6_4.1.x86_64 libcom_err-1.41.12-14.el6_4.2.x86_64 libselinux-2.0.94-5.3.el6.x86_64 nss-softokn-freebl-3.12.9-11.el6.x86_64 openssl-1.0.0-27.el6_4.2.x86_64 pcre-7.8-6.el6.x86_64 zlib-1.2.3-29.el6.x86_64

(gdb) n

133 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));

(gdb) n

134 if (ctx == NULL) {

(gdb) n

138 (ngx_http_conf_ctx_t *) conf = ctx;

(gdb) p *cf

$1 = {name = 0x0, args = 0x760db8, cycle = 0x75fc30, pool = 0x75fbe0, temp_pool = 0x763bf0, conf_file = 0x7fffffffdf80, log = 0x730960, ctx = 0x7609f8,

module_type = 1163022147, cmd_type = 16777216, handler = 0, handler_conf = 0x0}

(gdb) p *cf->conf_file->buffer ############加载配置

$2 = {

pos = 0x767d54 "\n include mime.types;\n default_type application/octet-stream;\n\n #log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n #", ' ' <repeats 18 times>, "'$status $body_bytes_s"..., last = 0x76888e "", file_pos = 16384, file_last = 221589780121,

start = 0x767c00 "user fanhy;\nworker_processes 1;\n\nerror_log logs/nginxdubug_error.log debug_http;\n#error_log logs/nginxdubug_error.log debug_core;\n#error_log logs/nginxdubug_error.log debug_http;\n\n#error_log log"..., end = 0x768c00 "", tag = 0x0, file = 0x419335, shadow = 0x0, temporary = 1, memory = 0,

mmap = 0, recycled = 0, in_file = 1, flush = 1, sync = 1, last_buf = 1, last_in_chain = 1, last_shadow = 1, temp_file = 0, num = 0}


http框架初始化,配置文件解析


HTTP框架执行流程

对于nginx来说,一个请求是从ngx_http_init_request开始的。

解析请求行

ngx_http_init_request这个函数中,会设置读事件为ngx_http_process_request_line,也就是说,接下来的网络事件,会由ngx_http_process_request_line来执行。从ngx_http_process_request_line的函数名,我们可以看到,这就是来处理请求行的,正好与之前讲的,处理请求的第一件事就是处理请求行是一致的。通过ngx_http_read_request_header来读取请求数据。然后调用ngx_http_parse_request_line函数来解析请求行。

nginx为提高效率,采用状态机来解析请求行,而且在进行method的比较时,没有直接使用字符串比较,而是将四个字符转换成一个整形,然后一次比较以减少cpu的指令数,这个前面有说过。很多人可能很清楚一个请求行包含请求的方法,uri,版本,却不知道其实在请求行中,也是可以包含有host的。比如一个请求GET http://www.taobao.com/uri HTTP/1.0这样一个请求行也是合法的,而且host是www.taobao.com,这个时候,nginx会忽略请求头中的host域,而以请求行中的这个为准来查找虚拟主机。另外,对于对于http0.9版来说,是不支持请求头的,所以这里也是要特别的处理。所以,在后面解析请求头时,协议版本都是1.0或1.1。整个请求行解析到的参数,会保存到ngx_http_request_t结构当中。

解析请求头

在解析完请求行后,nginx会设置读事件的handler为ngx_http_process_request_headers,然后后续的请求就在ngx_http_process_request_headers中进行读取与解析。ngx_http_process_request_headers函数用来读取请求头,跟请求行一样,还是调用ngx_http_read_request_header来读取请求头,调用ngx_http_parse_header_line来解析一行请求头,解析到的请求头会保存到ngx_http_request_t的域headers_in中,headers_in是一个链表结构,保存所有的请求头。而HTTP中有些请求是需要特别处理的,这些请求头与请求处理函数存放在一个映射表里面,即ngx_http_headers_in,在初始化时,会生成一个hash表,当每解析到一个请求头后,就会先在这个hash表中查找,如果有找到,则调用相应的处理函数来处理这个请求头。比如:Host头的处理函数是ngx_http_process_host。

处理请求

当nginx解析到两个回车换行符时,就表示请求头的结束,此时就会调用ngx_http_process_request来处理请求了。

ngx_http_process_request会设置当前的连接的读写事件处理函数为ngx_http_request_handler,然后再调用ngx_http_handler来真正开始处理一个完整的http请求。这里可能比较奇怪,读写事件处理函数都是ngx_http_request_handler,其实在这个函数中,会根据当前事件是读事件还是写事件,分别调用ngx_http_request_t中的read_event_handler或者是write_event_handler。由于此时,我们的请求头已经读取完成了,之前有说过,nginx的做法是先不读取请求body,所以这里面我们设置read_event_handler为ngx_http_block_reading,即不读取数据了。刚才说到,真正开始处理数据,是在ngx_http_handler这个函数里面,这个函数会设置write_event_handler为ngx_http_core_run_phases,并执行ngx_http_core_run_phases函数。

ngx_http_core_run_phases这个函数将执行多阶段请求处理,nginx将一个http请求的处理分为多个阶段,那么这个函数就是执行这些阶段来产生数据。因为ngx_http_core_run_phases最后会产生数据,所以我们就很容易理解,为什么设置写事件的处理函数为ngx_http_core_run_phases了。

在这里,我简要说明了一下函数的调用逻辑,我们需要明白最终是调用ngx_http_core_run_phases来处理请求,产生的响应头会放在ngx_http_request_t的headers_out中,这一部分内容,我会放在请求处理流程里面去讲。

nginx的各种阶段会对请求进行处理,最后会调用filter来过滤数据,对数据进行加工,如truncked传输、gzip压缩等。这里的filter包括headerfilter与body filter,即对响应头或响应体进行处理。filter是一个链表结构,分别有header filter与body filter,先执行header filter中的所有filter,然后再执行body filter中的所有filter。在header filter中的最后一个filter,即ngx_http_header_filter,这个filter将会遍历所的有响应头,最后需要输出的响应头的一个连续的内存,然后调用ngx_http_write_filter进行输出。ngx_http_write_filter是body filter中的最后一个,所以nginx首先的body信息,在经过一系列的body filter之后,最后也会调用ngx_http_write_filter来进行输出。

这里要注意的是,nginx会将整个请求头都放在一个buffer里面,这个buffer的大小通过配置项client_header_buffer_size来设置,如果用户的请求头太大,这个buffer装不下,那nginx就会重新分配一个新的更大的buffer来装请求头,这个大buffer可以通过large_client_header_buffers来设置,这个large_buffer这一组buffer,比如配置4 8k,就是表示有四个8k大小的buffer可以用。注意,为了保存请求行或请求头的完整性,一个完整的请求行或请求头,需要放在一个连续的内存里面,所以,一个完整的请求行或请求头,只会保存在一个buffer里面。这样,如果请求行大于一个buffer的大小,就会返回414错误,如果一个请求头大小大于一个buffer大小,就会返回400错误。在了解了这些参数的值,以及nginx实际的做法之后,在应用场景,我们就需要根据实际的需求来调整这些参数,来优化我们的程序了。

© 著作权归作者所有

Foyon
粉丝 4
博文 8
码字总数 7357
作品 0
海淀
程序员
私信 提问
nginx源码分析—启动流程

作者:阿波 本文链接: http://blog.csdn.net/livelylittlefish/article/details/7243718 Content 0. 序 1. main()分析 2. 注意问题 2.1 几个初值 2.2 nginx工作模式 2.3 一些配置 2.4 其他开...

晨曦之光
2012/03/09
1K
0
nginx源码分析——配置

配置介绍 nginx的配置由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,这些配置文件全部位于nginx安装目录下的conf目录中。 主配置文件nginx.conf中的内容大概是...

hncscwc
2016/06/13
194
0
nginx源码分析——模块

模块介绍 高度模块化的设计是nginx的架构基础。在nginx中,除了少量的核心代码,其他一切皆为模块。这种模块化设计同时具有以下几个特点: 高度抽象的模块接口 所有的模块都遵循着同样的 ng...

hncscwc
2016/06/17
120
0
SEnginx 开发版本 1.5.10 发布

SEnginx开发版本1.5.10发布,此版本中主要增加访问行为识别模块、带条件的 limit_req 模块等功能。 具体如下: *) Feature: 升级到原始nginx 1.5.10 版本,此版本的 nginx 支持 SPDY 3.1 协议...

InfoHunter
2014/02/10
1K
0
Nginx filter 模块解析

我们知道nginx很多功能都是通过filter模块来实现的,如:替换content的sub module、content压缩的gzip module等。接下去我们看看nginx是怎样处理filter模块的。 Nginx filter module所有的代...

mickelfeng
2012/12/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

搭建tftp服务

前言: 最近整理一些以前的学习笔记。 过去都是存储在本地,此次传到网络留待备用。 TFTP服务: TFTP:Trivial File Transfer Protocol 不重要文件传输协议 主要用来传送小文件,不支持认证和...

迷失De挣扎
今天
4
0
rest 的理解

rest:表现层状态转移。 什么是restful协议?https://en.wikipedia.org/wiki/Representational_state_transfer 使用restful的好处。 Rest是一种体系结构样式,他定义了一组用于创建web服务的...

xiaoxiao_go
今天
5
0
聊聊spring cloud的CachingSpringLoadBalancerFactory

序 本文主要研究一下spring cloud的CachingSpringLoadBalancerFactory CachingSpringLoadBalancerFactory spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/o......

go4it
昨天
6
0
一篇文章搞定——JDK8中新增的StampedLock

一、StampedLock类简介 StampedLock类,在JDK1.8时引入,是对读写锁ReentrantReadWriteLock的增强,该类提供了一些功能,优化了读锁、写锁的访问,同时使读写锁之间可以互相转换,更细粒度控...

须臾之余
昨天
5
0
Android Camera原理之CameraDeviceCallbacks回调模块

在讲解《Android Camera原理之openCamera模块(二)》一文的时候提到了CameraDeviceCallbacks回调,当时没有详细展开,本文我们详细展开讲解一下。 CameraDeviceCallbacks生成过程: 《Android...

天王盖地虎626
昨天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部