11.Nginx启动流程之ngx_add_inherited_sockets

来源:互联网 发布:hash 源码 编辑:程序博客网 时间:2024/06/02 04:20

Nginx的启动流程在ngx_os_init后,会调用ngx_add_inherited_sockets对继承的套接字描述符进行处理,下面对这个步骤进行代码分析:


/* core/ngx_string.c *//* 将一串由数字组成的十进制字符串转换为整数   param line: 字符串的首地址            n: 字符串长度*/ngx_int_t ngx_atoi(u_char *line, size_t n){    ngx_int_t  value;    if (n == 0) {        return NGX_ERROR;    }    for (value = 0; n--; line++) {        if (*line < '0' || *line > '9') {            // 如果字符串中包含数字以外的字符, 说明是非法字符串, 返回NGX_ERROR            return NGX_ERROR;        }        // value乘以10, 然后加上当前字符对应的数值        value = value * 10 + (*line - '0');    }    // 返回value, 一般来说value不可能为负值    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}/* core/ngx_inet.c *//* 将字符转换为十进制字符串形式   param text: 用于存放结果的缓冲区            c: 待转换的字符          len: 缓冲区大小   return    : 字符串结果长度*/ngx_inline static size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len){    size_t      n;    ngx_uint_t  c1, c2;    // n用于记录转换后的字符串长度    n = 0;    if (len == n) {        return n;    }    // 求取百位数值    c1 = c / 100;    if (c1) {        // 如果百位数值不为0, 那么将其对应的字符形式存入缓冲区        *text++ = (u_char) (c1 + '0');        n++;        if (len == n) {            // 说明缓冲区已满, 直接返回            return n;        }    }    // 求取十位数值    c2 = (c % 100) / 10;    if (c1 || c2) {        // 如果百位为非0或者百位为0十位不为0, 那么缓冲区存入十位数值对应的字符;        // 假设十位为0, 那么是否存入'0'取决于百位是否为0, 所以不能仅仅判断c2是否为0        *text++ = (u_char) (c2 + '0');        n++;        if (len == n) {            return n;        }    }    // 求取个位数值    c2 = c % 10;    // 缓冲区存入个位数值对应的字符    *text++ = (u_char) (c2 + '0');    n++;    // 返回转换后的字符串长度    return n;}/* 将套接字地址转换为点分十进制字符串形式, 这里类似inet_ntop库函数的作用   param family: 协议族           addr: 通用套接字地址结构体指针           text: 指向用于存放字符串结果的内存空间            len: 用于存放字符串结果的内存空间字节大小   return      : 字符串结果长度*/size_t ngx_sock_ntop(int family, struct sockaddr *addr, u_char *text,                     size_t len){    u_char              *p;    size_t               n;    // 用于记录转换后的字符串长度    ngx_uint_t           i;    struct sockaddr_in  *addr_in;    if (len == 0) {        return 0;    }    if (family != AF_INET) {        // 目前只支持IPv4协议族        return 0;    }    addr_in = (struct sockaddr_in *) addr;    p = (u_char *) &addr_in->sin_addr;    if (len > INET_ADDRSTRLEN) {        len = INET_ADDRSTRLEN;    }    // 将IPv4二进制地址的第一个字节转换为相应的十进制字符串    n = ngx_sprint_uchar(text, p[0], len);    i = 1;    do {        if (len == n) {            // 如果缓冲区已耗尽, 那么置最后一个字节为0, 用来表示字符串结尾            text[n - 1] = '\0';            return n;        }        // 在当前缓冲区位置存入'.'分隔符        text[n++] = '.';        if (len == n) {            // 如果缓冲区已耗尽, 那么置最后一个字节为0, 用来表示字符串结尾            text[n - 1] = '\0';            return n;        }        // 转换IPv4二进制地址的下一个字节        n += ngx_sprint_uchar(&text[n], p[i++], len - n);    } while (i < 4);    if (len == n) {        text[n] = '\0';        return n;    }    text[n] = '\0';    return n;#if 0    return ngx_snprintf((char *) text,                        len > INET_ADDRSTRLEN ? INET_ADDRSTRLEN : len,                        "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);#endif}/* core/ngx_connection.c *//* 设置继承的套接字描述符   param cycle: ngx_cycle_t结构体指针*/ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle){    ngx_uint_t           i;    ngx_listening_t     *ls;    struct sockaddr_in  *addr_in;    ls = cycle->listening.elts;    // 遍历cycle的listening数组, listening数组中存放了继承的套接字描述符    for (i = 0; i < cycle->listening.nelts; i++) {        // 从cycle使用的内存池中申请一块sockaddr_in结构体大小的内存,        // 从这里可以看出Nginx只支持继承IPv4套接字描述符        ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(struct sockaddr_in));        if (ls[i].sockaddr == NULL) {            // 内存申请失败, 返回NGX_ERROR            return NGX_ERROR;        }        // ngx_listening_t结构体的socklen成员用于记录套接字地址结构的长度        ls[i].socklen = sizeof(struct sockaddr_in);        // 调用getsockname库函数获取套接字描述符的本地地址        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);            // 获取本地地址失败, 置ngx_listening_t结构体的ignore成员为1, 即表示忽略            ls[i].ignore = 1;            continue;        }        addr_in = (struct sockaddr_in *) ls[i].sockaddr;        // 验证本地地址的协议族是否为AF_INET, 上面说过只支持IPv4        if (addr_in->sin_family != AF_INET) {            ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,                          "the inherited socket #%d has "                          "unsupported family", ls[i].fd);            ls[i].ignore = 1;            continue;        }        // INET_ADDRSTRLEN宏表示一个IPv4地址的点分十进制字符串形式的最大长度, 包括结束符'\0',        // "255.255.255.255"的长度为15, 那么INET_ADDRSTRLEN就是16        ls[i].addr_text_max_len = INET_ADDRSTRLEN;        // 从cycle使用的内存池中申请一块大小为INET_ADDRSTRLEN的内存        ls[i].addr_text.data = ngx_palloc(cycle->pool, ls[i].addr_text_max_len);        if (ls[i].addr_text.data == NULL) {            return NGX_ERROR;        }        // ngx_listening_t结构体的family成员用于记录协议族        ls[i].family = addr_in->sin_family;        // 将本地地址转换为点分十进制字符串形式, 并存放在ngx_listening_t结构体的addr_text成员中        ls[i].addr_text.len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr,                                            ls[i].addr_text.data,                                            ls[i].addr_text_max_len);        if (ls[i].addr_text.len == 0) {            // 如果转换后的点分十进制字符串长度为0, 意味着出错, 返回NGX_ERROR            return NGX_ERROR;        }    }    return NGX_OK;}/* core/nginx.c *//* 添加继承的套接字描述符到cycle   param cycle: ngx_cycle_t结构体指针*/static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle){    u_char              *p, *v, *inherited;    ngx_socket_t         s;    ngx_listening_t     *ls;    // 调用getenv库函数从环境变量中获取NGINX_VAR的值    // NGINX_VAR就是字符串"NGINX"的宏    inherited = (u_char *) getenv(NGINX_VAR);    // 如果环境变量中没有指定NGINX的值, 那么意味着没有指定继承的套接字描述符, 直接返回    if (inherited == NULL) {        return NGX_OK;    }    ngx_log_error(NGX_LOG_INFO, cycle->log, 0,                  "using inherited sockets from \"%s\"", inherited);    // 初始化cycle中的listening数组, 这个数组的元素都是ngx_listening_t结构体, 初始容量为10    ngx_init_array(cycle->listening, cycle->pool,                   10, sizeof(ngx_listening_t), NGX_ERROR);    // 遍历环境变量中NGINX的值, 用来解析出待继承的套接字描述符    for (p = inherited, v = p; *p; p++) {        // 如果p指向的字符不是:或者;, 那么指向下一个字符        if (*p == ':' || *p == ';') {            // 当p指向:或者;时, 说明[v, p-1]之间包含的是一个套接字描述符的十进制字符串形式,            // 所以待传递的套接字描述符在环境变量中的表示类似"10:11:12"或者"10;11;12"                        // 将套接字描述符的十进制字符串形式转换为整数            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 " enviroment variable, "                              "ignoring the rest of the variable", v);                break;            }            // 解析完一个套接字描述符, 那么v指向p+1, 也就是下一个套接字描述符的起始字符            v = p + 1;            // 从cycle的listening数组中分配一个ngx_listening_t结构体大小的内存            if (!(ls = ngx_push_array(&cycle->listening))) {                return NGX_ERROR;            }            // 记录刚解析的套接字描述符            ls->fd = s;        }    }    // 置全局变量ngx_inherited为1    ngx_inherited = 1;    // 调用ngx_set_inherited_sockets对继承的套接字描述符进行设置    return ngx_set_inherited_sockets(cycle);}


原创粉丝点击