您的位置:首页 > 运维架构 > Nginx

11.Nginx启动流程之ngx_add_inherited_sockets

2017-10-30 16:24 375 查看
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
, p[i++], len - n);

} while (i < 4);

if (len == n) {
text
= '\0';
return n;
}

text
= '\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) {
// 内存申请
b93e
失败, 返回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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: