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);}
阅读全文
0 0
- 11.Nginx启动流程之ngx_add_inherited_sockets
- nginx启动流程之master进程初始化
- nginx启动流程之work初始化
- 10.Nginx启动流程之ngx_os_init
- 12.Nginx启动流程之ngx_init_cycle
- Nginx学习之十一-Nginx启动框架处理流程
- Nginx学习之十一-Nginx启动框架处理流程
- Nginx学习之十一-Nginx启动框架处理流程
- Nginx学习之十一-Nginx启动框架处理流程
- Nginx启动初始化流程
- 【Nginx】启动流程
- Nginx启动流程
- Nginx启动框架处理流程
- Nginx学习笔记(十三):Nginx启动流程
- Nginx学习(12)—Nginx启动流程
- nginx学习十一 nginx启动流程
- nginx的启动流程和接客流程
- nginx源码分析—启动流程
- 中国传统文化课程笔记
- 自动检测版本更新的流程
- SpringMVC的工作原理
- 技术分享:基于 Kubernetes 的 AI 训练实践
- matlab2014调用vs2015进行混合编译生成mex文件
- 11.Nginx启动流程之ngx_add_inherited_sockets
- MXNet官方文档中文版教程(5):加载数据(Iterators)
- MACS原理,使用,结果文件解析
- Oracle 11g中管理员用户sys,system密码不可用解决办法
- mysql 浅谈
- 畅通工程(并查集)
- 迭代器
- Android ViewFlipper类
- 循环调用FTP通信时遇到的问题