nginx 代码分析listen 和request请求的流程
2017-04-28 15:05
274 查看
listen 针对于server的端口进行监听,server的配置可以比较复杂如:
host配置:
ngx_http_add_listen 函数将解析http中的server的地址和端口,以port为粒度,添加addr(即1.1.1.1:80、2.2.2.2:80和80,会放在相同的cmcf->port[i]中)。
时序图和数据结构关系图:
那么在cmcf中的存储例子:
然后,就是在ngx_http_optimize_servers 中优化后加入cf->cycle->listening中(待完善)
接着在ngx_init_cycle –> ngx_open_listening_sockets中打开和监听所有的端口创建socket
在启动过程中的 ngx_worker_process_init中调用ngx_modules[event]->init_process(cycle) 初始化connections 并设置事件的回调 ,以ngx_epoll_moudle为例:
ngx_event_process_init中 listen流程
ngx_event_accept请求的处理流程
-这里涉及到ngx_use_accept_mutex的问题,用于解决多进程之间对请求的均衡处理(后续理解)
具体的时序图:
ngx_http_wait_request_handler
当epoll中此connection可读,调用ngx_http_wait_request_handler(ngx_event_t *rev)
关于rev和connection中的关键数据data的关系
ngx_get_connection中 rev->data = c;
ngx_http_init_connection(*c) -> ngx_http_wait_request_handler(rev) -> c->data = ngx_http_create_request(rev)
最后当请求request过来的时候就能够从rev中获取到request并且里面有相应的ngx_http_core_loc_conf_t
ngx_http_core_find_location 回顾上一篇文章中,根据url和ngx_http_core_loc_conf_t 的三叉排序树或者正则数组 来获取正确模块的loc_conf。
最后就可以调用模块的content_handler函数传入req->locf 完成整请求(待完善)
后续会针对初始化event 和 请求的流程写详细一点,这里只是从listen出发后续展开。
server { listen 192.168.8.81:80; server_name vae.test1.com *.test1.com;<!--hosts文件配置的地址--> index index.html; location /test1 { root /usr/local/nginx/html/; } } server { listen 127.0.0.1:80; server_name vae.test1.com *.test1.com;<!--hosts文件配置的地址--> index index.html; location /test1 { root /usr/local/nginx/html/; } } server { listen 80; server_name vae.test1.com;<!--hosts文件配置的地址--> index index.html; location /test1 { root /usr/local/nginx/html/; } } server { listen 80; server_name vae.test2.com; index index.html; location /test2 { root /usr/local/nginx/html/; } } server { listen 8081; server_name vae.test3.com; index index.html; location /test3 { root /usr/local/nginx/html/; } } //完成之后需要重新启动下nginx命令:nginx -s reload,每次修改nginx.conf文件都需要重启
host配置:
# 127.0.0.1 localhost # ::1 localhost 192.168.8.81 vae.test1.com 192.168.8.81 vae.test2.com 192.168.8.81 vae.test3.com
ngx_http_add_listen 函数将解析http中的server的地址和端口,以port为粒度,添加addr(即1.1.1.1:80、2.2.2.2:80和80,会放在相同的cmcf->port[i]中)。
时序图和数据结构关系图:
那么在cmcf中的存储例子:
然后,就是在ngx_http_optimize_servers 中优化后加入cf->cycle->listening中(待完善)
接着在ngx_init_cycle –> ngx_open_listening_sockets中打开和监听所有的端口创建socket
在启动过程中的 ngx_worker_process_init中调用ngx_modules[event]->init_process(cycle) 初始化connections 并设置事件的回调 ,以ngx_epoll_moudle为例:
ngx_event_process_init中 listen流程
/* 初始化用来管理所有定时器的红黑树,用于事件的处理轮询 */ if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } .... //分配和初始化cycle->connections,设置每个c的读写事件event cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); c = cycle->connections; cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,cycle->log); cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,cycle->log); do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; //关联c[i]和rev wev c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; } while (i); //针对监听的每个端口,分配connecting,并设置回调函数,加入到epoll池中 //c = ngx_cycle->free_connections; ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log); .... rev->handler = ngx_event_accept; if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } }
ngx_event_accept请求的处理流程
-这里涉及到ngx_use_accept_mutex的问题,用于解决多进程之间对请求的均衡处理(后续理解)
//epoll 中接收到请求后的回调,建立socket连接 void ngx_event_accept(ngx_event_t *ev) { lc = ev->data; ls = lc->listening; s = accept(lc->fd, (struct sockaddr *) sa, &socklen); if (ngx_use_accept_mutex) {//进程竞争锁 if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); ngx_accept_mutex_held = 0; } ngx_accept_disabled = 1; } else { ngx_add_timer(ev, ecf->accept_mutex_delay); } c = ngx_get_connection(s, ev->log); } //加入到epoll中等待read事件 if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { ngx_close_accepted_connection(c); return; } } //在ngx_http_add_listening时ls->handler = ngx_http_init_connection;设置回调 ls->handler(c);//初始化这个对话connection
void ngx_http_init_connection(ngx_connection_t *c) {//初始化一个request的connection //设置这个listen的addr_conf和conf_ctx,当数据可读时候用于解析 hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); if (hc == NULL) { ngx_http_close_connection(c); return; } c->data = hc; .... rev = c->read;//初始化read的epoll毁掉函数 rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; //设置这个链接的超时timer ngx_add_timer(rev, c->listening->post_accept_timeout); }
具体的时序图:
ngx_http_wait_request_handler
当epoll中此connection可读,调用ngx_http_wait_request_handler(ngx_event_t *rev)
关于rev和connection中的关键数据data的关系
//request 中的main_conf/srv_conf/loc_conf ngx_http_wait_request_handler(ngx_event_t *rev) { n = c->recv(c, b->last, size); .... c->data = ngx_http_create_request(c); //这里创建request { r->main_conf = hc->conf_ctx->main_conf; r->srv_conf = hc->conf_ctx->srv_conf; r->loc_conf = hc->conf_ctx->loc_conf; } }
ngx_get_connection中 rev->data = c;
ngx_http_init_connection(*c) -> ngx_http_wait_request_handler(rev) -> c->data = ngx_http_create_request(rev)
//设置request 的connect到recv中: ngx_http_process_request_line(ngx_event_t *rev) { ngx_connection_t *c; ngx_http_request_t *r; c = rev->data; //ngx_get_connection中 rev->data = c; r = c->data; //这里的data设置:ngx_http_init_connection(*c) -> ngx_http_wait_request_handler(rev) -> c->data = ngx_http_create_request(rev) }
最后当请求request过来的时候就能够从rev中获取到request并且里面有相应的ngx_http_core_loc_conf_t
ngx_http_core_find_location 回顾上一篇文章中,根据url和ngx_http_core_loc_conf_t 的三叉排序树或者正则数组 来获取正确模块的loc_conf。
最后就可以调用模块的content_handler函数传入req->locf 完成整请求(待完善)
后续会针对初始化event 和 请求的流程写详细一点,这里只是从listen出发后续展开。
相关文章推荐
- nginx记录分析网站响应慢的请求(ngx_http_log_request_speed)
- nginx记录分析网站响应慢的请求(ngx_http_log_request_speed)
- nginx源码码分析--请求头的接受流程(1)
- nginx记录分析网站响应慢的请求(ngx_http_log_request_speed)
- SpringMVC4.x源码分析(四):一个request请求的完整流程和各组件介绍
- nginx记录分析网站响应慢的请求(ngx_http_log_request_speed)
- nginx记录分析网站响应慢的请求(ngx_http_log_request_speed)
- nginx源码分析--请求头接受流程(2)
- nginx记录分析网站响应慢的请求(ngx_http_log_request_speed)
- nginx代码分析--启动流程
- Nginx 多进程连接请求/事件分发流程分析
- BT源代码学习心得(八):跟踪服务器(Tracker)的代码分析(用户请求的实际处理) - 转贴自 wolfenstein (NeverSayNever)
- Android GSM驱动模块(rild)详细分析(二)request流程
- dm9000驱动代码流程分析
- 内核的创建流程与代码分析
- wince dm9000驱动代码流程分析--转载
- Yii请求处理流程分析
- JavaScript下通过的XMLHttpRequest发送请求的代码
- Zend framework处理一个http请求的流程分析
- Zend framework处理一个http请求的流程分析