ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { char **env, *var; u_char *p; ngx_uint_t i, n; ngx_pid_t pid; ngx_exec_ctx_t ctx; ngx_core_conf_t *ccf; ngx_listening_t *ls; ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t)); ctx.path = argv[0]; ctx.name = "new binary process"; ctx.argv = argv; n = 2; env = ngx_set_environment(cycle, &n); if (env == NULL) { return NGX_INVALID_PID; } var = ngx_alloc(sizeof(NGINX_VAR) + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, cycle->log); if (var == NULL) { ngx_free(env); return NGX_INVALID_PID; } p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR)); ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { p = ngx_sprintf(p, "%ud;", ls[i].fd); } *p = '\0'; env[n++] = var; #if (NGX_SETPROCTITLE_USES_ENV) /* allocate the spare 300 bytes for the new binary process title */ env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; #endif env[n] = NULL; #if (NGX_DEBUG) { char **e; for (e = env; *e; e++) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e); } } #endif ctx.envp = (char *const *) env; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s to %s failed " "before executing new binary process \"%s\"", ccf->pid.data, ccf->oldpid.data, argv[0]); ngx_free(env); ngx_free(var); return NGX_INVALID_PID; } pid = ngx_execute(cycle, &ctx); if (pid == NGX_INVALID_PID) { if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s back to %s failed after " "an attempt to execute new binary process \"%s\"", ccf->oldpid.data, ccf->pid.data, argv[0]); } } ngx_free(env); ngx_free(var); return pid; }
src/core/nginx.c 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; //获取环境变量 这里的"NGINX_VAR"是宏定义,值为"NGINX" 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); //初始化ngx_cycle.listening数组,而且数组中包含10个元素 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++) { //环境变量的值以':'or';'分开 if (*p == ':' || *p == ';') { //转换十进制sockets 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; //返回新分配的数组指针地址(在参考的blog里面这里解释可能有点错误) ls = ngx_array_push(&cycle->listening); if (ls == NULL) { return NGX_ERROR; } //初始化内存空间 ngx_memzero(ls, sizeof(ngx_listening_t)); //保存socket文件描述符到数组中 ls->fd = (ngx_socket_t) s; } } ngx_inherited = 1; //表示已经的获得要继承的socket //接下来详细讲解的函数 return ngx_set_inherited_sockets(cycle); } /* 根据上面的讲解,大体能够知道这个方法的用途: 主要是读取环境变量"NGINX" 将其中各个用分隔符":"or";"的数值, 保存在ngx_cycel->listening数组中 */
src/core/ngx_connection.c ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) { size_t len; ngx_uint_t i; ngx_listening_t *ls; socklen_t olen; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_err_t err; struct accept_filter_arg af; #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) int timeout; #endif //取出cycle->listening数组中的数据地址 ls = cycle->listening.elts; //遍历数组 //要记得以前讲过数组当中存放的是ngx_listening_t结构体 for (i = 0; i < cycle->listening.nelts; i++) { //ls的fd已经在以前赋值了 //sockaddr分配内存空间 ls[i].sockaddr = ngx_palloc(cycle->pool, NGX_SOCKADDRLEN); if (ls[i].sockaddr == NULL) { return NGX_ERROR; } ls[i].socklen = NGX_SOCKADDRLEN; //获取socket名字,要用于判断是否有效 if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "getsockname() of the inherited " "socket #%d failed", ls[i].fd); ls[i].ignore = 1; continue; } //查看sockaddr 地址族类型 根据类型设置最大长度 switch (ls[i].sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN; len = NGX_UNIX_ADDRSTRLEN; break; #endif case AF_INET: ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; break; default: ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "the inherited socket #%d has " "an unsupported protocol family", ls[i].fd); ls[i].ignore = 1; continue; } ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len); if (ls[i].addr_text.data == NULL) { return NGX_ERROR; } //以前的长度主要为了下面的转换作准备 //将socket绑定的地址转换为文本格式(ipv4和ipv6的不相同) len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, len, 1); if (len == 0) { return NGX_ERROR; } ls[i].addr_text.len = len; //这里设置类每一个监听的socket的backlog为511 ls[i].backlog = NGX_LISTEN_BACKLOG; olen = sizeof(int); //获取文件描述符的接受缓冲区大小,并用rcvbuf保存,而且指定rcvbuf大小olen if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf, &olen) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "getsockopt(SO_RCVBUF) %V failed, ignored", &ls[i].addr_text); ls[i].rcvbuf = -1; } olen = sizeof(int); //获取文件描述符发送缓冲区大小,并用sndbuf保存,而且指定sndbuf大小olen if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf, &olen) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "getsockopt(SO_SNDBUF) %V failed, ignored", &ls[i].addr_text); ls[i].sndbuf = -1; } #if 0 /* SO_SETFIB is currently a set only option */ #if (NGX_HAVE_SETFIB) if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB, (void *) &ls[i].setfib, &olen) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "getsockopt(SO_SETFIB) %V failed, ignored", &ls[i].addr_text); ls[i].setfib = -1; } #endif #endif /* 当支持accept filter时,经过SO_ACCEPTFILTER选项取得socket的accept_filter表 保存在对应项的accept_filter中; 下面是SO_ACCEPTFILTER的解释(由于个人书里没有因此上网找的) SO_ACCEPTFILTER 是socket上的输入过滤,他在接手前 将过滤掉传入流套接字的连接,功能是服务器不等待 最后的ACK包而仅仅等待携带数据负载的包 */ #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_memzero(&af, sizeof(struct accept_filter_arg)); olen = sizeof(struct accept_filter_arg); if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen) == -1) { err = ngx_errno; if (err == NGX_EINVAL) { continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, "getsockopt(SO_ACCEPTFILTER) for %V failed, ignored", &ls[i].addr_text); continue; } if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') { continue; } ls[i].accept_filter = ngx_palloc(cycle->pool, 16); if (ls[i].accept_filter == NULL) { return NGX_ERROR; } (void) ngx_cpystrn((u_char *) ls[i].accept_filter, (u_char *) af.af_name, 16); #endif /* 若是当前操做系统TCP层支持TCP_DEFER_ACCEPT, 则试图获取TCP_DEFER_ACCEPT的timeout值。Timeout大于0时, 则将socket对应deferred_accept标志设为1 详细解释卸写在录里面了哦!!! */ #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) timeout = 0; olen = sizeof(int); if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen) == -1) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno, "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored", &ls[i].addr_text); continue; } if (olen < sizeof(int) || timeout == 0) { continue; } ls[i].deferred_accept = 1; #endif } return NGX_OK; }
能够看出html
ngx_add_inherited_sockets:主要是经过环境变量,获取到fd的值,而后存在数组当中;nginx
ngx_set_inherited_sockets:主要是对数组中的每个元素进行判断是否有效,而后进行初始化操做。数组
附录:服务器
TCP_DEFER_ACCEPT
我 们首先考虑的第1个选项是TCP_DEFER_ACCEPT(这是Linux系统上的叫法,其余一些操做系统上也有一样的选项但使用不一样的名字)。为了理 解TCP_DEFER_ACCEPT选项的具体思想,咱们有必要大体阐述一下典型的HTTP客户/服务器交互过程。请回想下TCP是如何与传输数据的目标创建链接的。在网络上,在分离的单元之间传输的信息称为IP包(或IP 数据报)。一个包总有一个携带服务信息的包头,包头用于内部协议的处理,而且它也能够携带数据负载。服务信息的典型例子就是一套所谓的标志,它把包标记表明TCP/IP协议栈内的特殊含义,例如收到包的成功确认等等。一般,在通过“标记”的包里携带负载是彻底可能的,但有时,内部逻辑迫使TCP/IP协议 栈发出只有包头的IP包。这些包常常会引起讨厌的网络延迟并且还增长了系统的负载,结果致使网络性能在总体上下降。网络
如今服务器建立了一个套接字同时等待链接。TCP/IP式的链接过程就是所谓“3次握手”。首先,客户程序发送一个设置SYN标志并且不带数据负载的TCP包(一个SYN包)。服务器则以发出带SYN/ACK标志的数据包(一个SYN/ACK包)做为刚才收到包的确认响应。客户随后发送一个ACK包确认收到了第2个包从而结束链接 过程。在收到客户发来的这个SYN/ACK包以后,服务器会唤醒一个接收进程等待数据到达。当3次握手完成后,客户程序即开始把“有用的”的数据发送给服务器。一般,一个HTTP请求的量是很小的并且彻底能够装到一个包里。可是,在以上的状况下,至少有4个包将用来进行双向传输,这样就增长了可观的延迟时间。此外,你还得注意到,在“有用的”数据被发送以前,接收方已经开始在等待信息了。socket
为了减轻这些问题所带来的影响,Linux(以及其余的 一些操做系统)在其TCP实现中包括了TCP_DEFER_ACCEPT选项。它们设置在侦听套接字的服务器方,该选项命令内核不等待最后的ACK包并且在第1个真正有数据的包到达才初始化侦听进程。在发送SYN/ACK包以后,服务器就会等待客户程序发送含数据的IP包。如今,只须要在网络上传送3个包 了,并且还显著下降了链接创建的延迟,对HTTP通讯而言尤为如此。函数
对于那些支持deffered accept的操做系统,nginx会设置这个参数来加强功能,设置了这个参数,在accept的时候,只有当实际收到了数据,才唤醒在accept等待的进程,能够减小一些无聊的上下文切换。性能
后半部分转自:ui
http://www.cnblogs.com/h2-database/archive/2012/05/23/2583263.htmlspa