Nginx初始化socket

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值