Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1471616
  • 博文数量: 150
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 3415
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-25 10:30
个人简介

游戏后台开发

文章分类

全部博文(150)

文章存档

2020年(1)

2019年(4)

2017年(3)

2016年(6)

2015年(4)

2014年(45)

2013年(86)

2012年(1)

分类: 服务器与存储

2013-11-06 23:28:58

Content

0.

1.侦听结构

2. ngx_add_inherited_sockets()分析

3. ngx_set_inherited_sockets()分析

4.小结

 

 

0.

 

本文将着重分析初始化过程中如何处理继承的sockets。文中如无特别说明,.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4

 

1.侦听结构

 

侦听结构较为复杂,描述如下。

 

file: ./src/core/ngx_connection.h

  1. typedef struct ngx_listening_s  ngx_listening_t;  
  2.   
  3. struct ngx_listening_s {  
  4.     ngx_socket_t        fd;         /* 文件描述符,即socket */  
  5.   
  6.     struct sockaddr    *sockaddr;   /* socket地址 */  
  7.     socklen_t           socklen;    /* size of sockaddr */  
  8.     size_t              addr_text_max_len;  
  9.     ngx_str_t           addr_text;  
  10.   
  11.     int                 type;  
  12.   
  13.     int                 backlog;  
  14.     int                 rcvbuf;     /* 接收缓冲区 */  
  15.     int                 sndbuf;     /* 发送缓冲区 */  
  16.   
  17.     /* handler of accepted connection */  
  18.     ngx_connection_handler_pt   handler;  
  19.   
  20.     void               *servers;  /* array of ngx_http_in_addr_t, for example */  
  21.   
  22.     ngx_log_t           log;  
  23.     ngx_log_t          *logp;  
  24.   
  25.     size_t              pool_size;  
  26.     /* should be here because of the AcceptEx() preread */  
  27.     size_t              post_accept_buffer_size;  
  28.     /* should be here because of the deferred accept */  
  29.     ngx_msec_t          post_accept_timeout;  
  30.   
  31.     ngx_listening_t    *previous;   /* 指向前一个ngx_listening_t结构 */  
  32.     ngx_connection_t   *connection;  
  33.   
  34.     unsigned            open:1;  
  35.     unsigned            remain:1;  
  36.     unsigned            ignore:1;  
  37.   
  38.     unsigned            bound:1;       /* already bound */  
  39.     unsigned            inherited:1;   /* inherited from previous process */  
  40.     unsigned            nonblocking_accept:1;  
  41.     unsigned            listen:1;  
  42.     unsigned            nonblocking:1;  
  43.     unsigned            shared:1;    /* shared between threads or processes */  
  44.     unsigned            addr_ntop:1;  
  45.   
  46. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)  
  47.     unsigned            ipv6only:2;  
  48. #endif  
  49.   
  50. #if (NGX_HAVE_DEFERRED_ACCEPT)  
  51.     unsigned            deferred_accept:1;  
  52.     unsigned            delete_deferred:1;  
  53.     unsigned            add_deferred:1;  
  54. #ifdef SO_ACCEPTFILTER  
  55.     char               *accept_filter;  
  56. #endif  
  57. #endif  
  58. #if (NGX_HAVE_SETFIB)  
  59.     int                 setfib;  
  60. #endif  
  61.   
  62. };  

sizeof(ngx_listening_t)=184。结构如下图。

ngx_listening_tngx_connection_t之间的关系如下图。

2. ngx_add_inherited_sockets()分析

 

该函数通过解析环境变量NGINX_VAR="NGINX",将其中的socket number保存至ngx_cycle.listening数组,该数组元素类型为ngx_listening_t。这些socekts在环境变量中以':'';'隔开。

 

例如,为调试方便,设环境变量NGINX为如下值

# export NGINX="16000:16500:16600;"

注意:当然,后续的测试并不一定会成功,此处只是为了分析该函数。例如,可能会出现如下错误。

nginx: [crit] getsockname() of the inherited socket #16000 failed (9: Bad file descriptor)

nginx: [crit] getsockname() of the inherited socket #16500 failed (9: Bad file descriptor)

nginx: [crit] getsockname() of the inherited socket #16600 failed (9: Bad file descriptor)

  1. /* 传入该参数的是init_cycle,调用ngx_init_cycle()后全局变量ngx_cycle会指向该结构 */  
  2. static ngx_int_t  
  3. ngx_add_inherited_sockets(ngx_cycle_t *cycle)  
  4. {  
  5.     u_char           *p, *v, *inherited;  
  6.     ngx_int_t         s;  
  7.     ngx_listening_t  *ls;  
  8.   
  9.     inherited = (u_char *) getenv(NGINX_VAR);  /* NGINX_VAR为宏,值为"NGINX" */  
  10.   
  11.     if (inherited == NULL) {  
  12.         return NGX_OK;  
  13.     }  
  14.   
  15.     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,  
  16.                   "using inherited sockets from \"%s\"", inherited);  
  17.   
  18.     if (ngx_array_init(&cycle->listening, cycle->pool, 10,  
  19.                        sizeof(ngx_listening_t))  
  20.         != NGX_OK)  /* 初始化ngx_cycle.listening数组, 10个元素空间 */  
  21.     {  
  22.         return NGX_ERROR;  
  23.     }  
  24.   
  25.     for (p = inherited, v = p; *p; p++) {  
  26.         if (*p == ':' || *p == ';') {  /* sockets以':'或者';'隔开 */  
  27.             s = ngx_atoi(v, p - v);    /* sockets是10进制正整数 */  
  28.             if (s == NGX_ERROR) {  
  29.                 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,  
  30.                               "invalid socket number \"%s\" in " NGINX_VAR  
  31.                               " environment variable, ignoring the rest"  
  32.                               " of the variable", v);  
  33.                 break;  
  34.             }  
  35.   
  36.             /* 第一次满足该条件时v和p分别指向如下值,此时解析出s=16000  
  37.                (gdb) p v 
  38.                $6 = (u_char *) 0x6b0139 "16000:16500:16600;" 
  39.                (gdb) p p 
  40.                $7 = (u_char *) 0x6b013e ":16500:16600;" 
  41.             */  
  42.             v = p + 1;  
  43.   
  44.             ls = ngx_array_push(&cycle->listening);  /* 将合法的socket number加入该数组*/  
  45.             if (ls == NULL) {  
  46.                 return NGX_ERROR;  
  47.             }  
  48.   
  49.             ngx_memzero(ls, sizeof(ngx_listening_t));  
  50.   
  51.             ls->fd = (ngx_socket_t) s;  /* 保存该socket至listening数组元素的fd字段 */  
  52.         }  
  53.     }  
  54.   
  55.     ngx_inherited = 1;  
  56.   
  57.     return ngx_set_inherited_sockets(cycle);  /* 该函数逐一设置cycle->listening数组每个元素 */  
  58. }  

调试过程中,得到以下信息,供参考。

[plain] view plaincopy
  1. (gdb) p cycle->listening  
  2. $11 = {elts = 0x6b02a0, nelts = 3, size = 184, nalloc = 10, pool = 0x6af650}  
  3. (gdb) x/w 0x6b02a0  
  4. 0x6b02a0:       16000  
  5. (gdb) x/w 0x6b0358  
  6. 0x6b0358:       16500  
  7. (gdb) x/w 0x6b0410  
  8. 0x6b0410:       16600  

可以验证,0x6b0358-0x6b02a0=0xB8=1840x6b0410-0x6b0358=0xB8=184

 

3. ngx_set_inherited_sockets()分析

 

该函数从参数cycle(后续调用ngx_init_cycle()函数后全局变量ngx_cycle会指向该参数)listening数组中逐一对每个元素(ngx_listening_t结构)进行初始化,即初始化除fd字段外的其他的字段。

 

因此,ngx_set_inherited_sockets()函数主要完成以下事情。

 

对全局变量ngx_cyclelistening数组,逐一设置该数组每个元素的以下字段

  • ls[i].sockaddr (调用getsockname())
  • ls[i].addr_text_max_len
  • ls[i].addr_text
  • ls[i].backlog
  • ls[i].rcvbuf (调用getsockopt())
  • ls[i].sndbuf (调用getsockopt())
  • ls[i].accept_filter
  • ls[i].deferred_accept

 

涉及到的相关系统函数调用如下。

  • getenv()获取环境变量,并返回指向该值字符串的指针;
  • getsockname()获取socket名字(地址及长度)
  • getsockopt()获取socket选项;

 

具体请参考附录或者源代码。

 

4.小结

 

本文主要分析初始化过程中如何处理继承的sockets

  

Reference

# man getenv

# mangetsockopt

# man getsockname

评论也很有用:

继承的SOCKET怎么来的呢?
后面看open_listening_sockets时,如果是继承来的socket就不用打开了,说明已经打开了。

请解释下,谢谢。 Re: xuqianghit 2013-03-10 10:16发表 [回复] 回复kingsun555:因为Nginx支持热切换可执行文件,为了保证在切换前后不丢失所监听的套接字,在切换之前Nginx会把当前的listen fds 写入环境变量,在切换以后通过读取环境变量获得这些listen fds 3楼 kingsun555 2012-08-02 22:41发表 [回复] ngx_add_inherited_sockets(),ngx_set_inherited_sockets()里面继承的sockets,似乎是从环境变量里面来的,直接赋值给了ngx_listening_t.fd,这有什么作用,不大明白,一般fd都是socket函数创建的,没见过这种。

阅读(2862) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~