ngx_add_inherited_sockets 创建socket实例,并对其初始化。
ngx_listening_s 数据结构类型:
struct ngx_listening_s {
ngx_socket_t fd;
struct sockaddr *sockaddr;
socklen_t socklen; /* size of sockaddr */
size_t addr_text_max_len;
ngx_str_t addr_text;
int type;
int backlog;
int rcvbuf;
int sndbuf;
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int keepidle;
int keepintvl;
int keepcnt;
#endif
/* handler of accepted connection */
ngx_connection_handler_pt handler;
void *servers; /* array of ngx_http_in_addr_t, for example */
ngx_log_t log;
ngx_log_t *logp;
size_t pool_size;
/* should be here because of the AcceptEx() preread */
size_t post_accept_buffer_size;
/* should be here because of the deferred accept */
ngx_msec_t post_accept_timeout;
ngx_listening_t *previous;
ngx_connection_t *connection;
ngx_rbtree_t rbtree;
ngx_rbtree_node_t sentinel;
ngx_uint_t worker;
unsigned open:1;
unsigned remain:1;
unsigned ignore:1;
unsigned bound:1; /* already bound */
unsigned inherited:1; /* inherited from previous process */
unsigned nonblocking_accept:1;
unsigned listen:1;
unsigned nonblocking:1;
unsigned shared:1; /* shared between threads or processes */
unsigned addr_ntop:1;
unsigned wildcard:1;
#if (NGX_HAVE_INET6)
unsigned ipv6only:1;
#endif
unsigned reuseport:1;
unsigned add_reuseport:1;
unsigned keepalive:2;
unsigned deferred_accept:1;
unsigned delete_deferred:1;
unsigned add_deferred:1;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
char *accept_filter;
#endif
#if (NGX_HAVE_SETFIB)
int setfib;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
int fastopen;
#endif
};
ngx_listening_s 类型实例创建及初始化过程:
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);
//从内存池cycle->pool中分配出10*sizeof(ngx_listening_t)大小的内存
if (ngx_array_init(&cycle->listening, cycle->pool, 10,
sizeof(ngx_listening_t))
!= NGX_OK)
{
return NGX_ERROR;
}
//遍历环境变量的值inherited该值是以“:”或者“;”分割的数值
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;
//从cycle->listening中分配出一个元素用于存储ngx_socket_t
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;
}
}
if (v != p) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
"invalid socket number \"%s\" in " NGINX_VAR
" environment variable, ignoring", v);
}
ngx_inherited = 1;
return ngx_set_inherited_sockets(cycle);
}
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 || NGX_HAVE_TCP_FASTOPEN)
ngx_err_t err;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
struct accept_filter_arg af;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
int timeout;
#endif
#if (NGX_HAVE_REUSEPORT)
int reuseport;
#endif
ls = cycle->listening.elts;
//遍历cycle->listening中的元素,并初始化
for (i = 0; i < cycle->listening.nelts; i++) {
//从内存池中申请sizeof(ngx_sockaddr_t)大小的空间
ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(ngx_sockaddr_t));
if (ls[i].sockaddr == NULL) {
return NGX_ERROR;
}
ls[i].socklen = sizeof(ngx_sockaddr_t);
//获取socket绑定的ip地址和端口
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;
}
if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
ls[i].socklen = sizeof(ngx_sockaddr_t);
}
//根据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].socklen,
¦ ¦ ¦ ¦ ¦ ¦ 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);
//获取监听的socket类型
¦ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type,
¦ ¦ ¦ ¦ ¦ &olen)
¦ ¦ == -1)
¦ {
¦ ¦ ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
¦ ¦ ¦ ¦ ¦ ¦ "getsockopt(SO_TYPE) %V failed", &ls[i].addr_text);
¦ ¦ ls[i].ignore = 1;
¦ ¦ continue;
¦ }
¦ olen = sizeof(int);
//获取socket接收缓冲区大小
¦ 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);
//获取socket的发送缓冲区大小
¦ 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
#if (NGX_HAVE_REUSEPORT)
¦ reuseport = 0;
¦ olen = sizeof(int);
#ifdef SO_REUSEPORT_LB
//获取socket的SO_REUSEPORT_LB属性
¦ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB,
¦ ¦ ¦ ¦ ¦ (void *) &reuseport, &olen)
¦ ¦ == -1)
¦ {
¦ ¦ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
¦ ¦ ¦ ¦ ¦ ¦ "getsockopt(SO_REUSEPORT_LB) %V failed, ignored",
¦ ¦ ¦ ¦ ¦ ¦ &ls[i].addr_text);
¦ } else {
¦ ¦ ls[i].reuseport = reuseport ? 1 : 0;
¦ }
#else
//获取socket的SO_REUSEPORT属性
//本选项允许完全重复的捆绑,不过只有在想要捆绑同一IP地址和端口的每个套接字都指定了本套接字选项才行
¦ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
¦ ¦ ¦ ¦ ¦ (void *) &reuseport, &olen)
¦ ¦ == -1)
¦ {
¦ ¦ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
¦ ¦ ¦ ¦ ¦ ¦ "getsockopt(SO_REUSEPORT) %V failed, ignored",
¦ ¦ ¦ ¦ ¦ ¦ &ls[i].addr_text);
¦ } else {
¦ ¦ ls[i].reuseport = reuseport ? 1 : 0;
¦ }
#endif
#endif
¦ if (ls[i].type != SOCK_STREAM) {
¦ ¦ continue;
¦ }
#if (NGX_HAVE_TCP_FASTOPEN)
¦ olen = sizeof(int);
//获取tcp协议TCP_FASTOPEN选型
¦ if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
¦ ¦ ¦ ¦ ¦ (void *) &ls[i].fastopen, &olen)
¦ ¦ == -1)
¦ {
¦ ¦ err = ngx_socket_errno;
¦ ¦ if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT
¦ ¦ ¦ && err != NGX_EINVAL)
¦ ¦ {
¦ ¦ ¦ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
¦ ¦ ¦ ¦ ¦ ¦ ¦ "getsockopt(TCP_FASTOPEN) %V failed, ignored",
¦ ¦ ¦ ¦ ¦ ¦ ¦ &ls[i].addr_text);
¦ ¦ }
¦ ¦ ls[i].fastopen = -1;
¦ }
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
¦ ngx_memzero(&af, sizeof(struct accept_filter_arg));
¦ olen = sizeof(struct accept_filter_arg);
//SO_ACCEPTFILTER 是socket上的输入过滤,他在接手前
//将过滤掉传入流套接字的链接,功能是服务器不等待
//最后的ACK包而仅仅等待携带数据负载的包
¦ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
¦ ¦ == -1)
¦ {
¦ ¦ err = ngx_socket_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
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
¦ timeout = 0;
¦ olen = sizeof(int);
//使用TCP_DEFER_ACCEPT可以减少用户程序hold的连接数,也可以减少用户调用epoll_ctl
//和epoll_wait的次数,从而提高了程序的性能。
//设置listen套接字的TCP_DEFER_ACCEPT选项后, 只当一个链接有数据时是才会从accpet中返回
//(而不是三次握手完成)。
¦ if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
¦ ¦ == -1)
¦ {
¦ ¦ err = ngx_socket_errno;
¦ ¦ if (err == NGX_EOPNOTSUPP) {
¦ ¦ ¦ continue;
¦ ¦ }
¦ ¦ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
¦ ¦ ¦ ¦ ¦ ¦ "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;
}