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
-
typedef struct ngx_listening_s ngx_listening_t;
-
-
struct ngx_listening_s {
-
ngx_socket_t fd;
-
-
struct sockaddr *sockaddr;
-
socklen_t socklen;
-
size_t addr_text_max_len;
-
ngx_str_t addr_text;
-
-
int type;
-
-
int backlog;
-
int rcvbuf;
-
int sndbuf;
-
-
-
ngx_connection_handler_pt handler;
-
-
void *servers;
-
-
ngx_log_t log;
-
ngx_log_t *logp;
-
-
size_t pool_size;
-
-
size_t post_accept_buffer_size;
-
-
ngx_msec_t post_accept_timeout;
-
-
ngx_listening_t *previous;
-
ngx_connection_t *connection;
-
-
unsigned open:1;
-
unsigned remain:1;
-
unsigned ignore:1;
-
-
unsigned bound:1;
-
unsigned inherited:1;
-
unsigned nonblocking_accept:1;
-
unsigned listen:1;
-
unsigned nonblocking:1;
-
unsigned shared:1;
-
unsigned addr_ntop:1;
-
-
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
-
unsigned ipv6only:2;
-
#endif
-
-
#if (NGX_HAVE_DEFERRED_ACCEPT)
-
unsigned deferred_accept:1;
-
unsigned delete_deferred:1;
-
unsigned add_deferred:1;
-
#ifdef SO_ACCEPTFILTER
-
char *accept_filter;
-
#endif
-
#endif
-
#if (NGX_HAVE_SETFIB)
-
int setfib;
-
#endif
-
-
};
sizeof(ngx_listening_t)=184。结构如下图。
ngx_listening_t与ngx_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)
-
-
static ngx_int_t
-
ngx_add_inherited_sockets(ngx_cycle_t *cycle)
-
{
-
u_char *p, *v, *inherited;
-
ngx_int_t s;
-
ngx_listening_t *ls;
-
-
inherited = (u_char *) getenv(NGINX_VAR);
-
-
if (inherited == NULL) {
-
return NGX_OK;
-
}
-
-
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
-
"using inherited sockets from \"%s\"", inherited);
-
-
if (ngx_array_init(&cycle->listening, cycle->pool, 10,
-
sizeof(ngx_listening_t))
-
!= NGX_OK)
-
{
-
return NGX_ERROR;
-
}
-
-
for (p = inherited, v = p; *p; p++) {
-
if (*p == ':' || *p == ';') {
-
s = ngx_atoi(v, p - v);
-
if (s == NGX_ERROR) {
-
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-
"invalid socket number \"%s\" in " NGINX_VAR
-
" environment variable, ignoring the rest"
-
" of the variable", v);
-
break;
-
}
-
-
-
-
-
-
-
-
v = p + 1;
-
-
ls = ngx_array_push(&cycle->listening);
-
if (ls == NULL) {
-
return NGX_ERROR;
-
}
-
-
ngx_memzero(ls, sizeof(ngx_listening_t));
-
-
ls->fd = (ngx_socket_t) s;
-
}
-
}
-
-
ngx_inherited = 1;
-
-
return ngx_set_inherited_sockets(cycle);
-
}
调试过程中,得到以下信息,供参考。
-
(gdb) p cycle->listening
-
$11 = {elts = 0x6b02a0, nelts = 3, size = 184, nalloc = 10, pool = 0x6af650}
-
(gdb) x/w 0x6b02a0
-
0x6b02a0: 16000
-
(gdb) x/w 0x6b0358
-
0x6b0358: 16500
-
(gdb) x/w 0x6b0410
-
0x6b0410: 16600
可以验证,0x6b0358-0x6b02a0=0xB8=184,0x6b0410-0x6b0358=0xB8=184。
3. ngx_set_inherited_sockets()分析
该函数从参数cycle(后续调用ngx_init_cycle()函数后全局变量ngx_cycle会指向该参数)的listening数组中逐一对每个元素(ngx_listening_t结构)进行初始化,即初始化除fd字段外的其他的字段。
因此,ngx_set_inherited_sockets()函数主要完成以下事情。
对全局变量ngx_cycle的listening数组,逐一设置该数组每个元素的以下字段
-
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函数创建的,没见过这种。
阅读(2913) | 评论(0) | 转发(0) |