Linux中listen()系统调用的backlog参数分析

这篇文章是对上一篇博客网络编程常用接口的内核实现----sys_listen()的补充(见  ),上篇文章中我说listen()系统调用的backlog参数既是连接队列的长度,也指定了半连接队列的长度(不能说等于),而不是《Unix网络编程》中讲到的是半连接队列和连接队列之和的上限,也就是说这个说法对Linux不适用。这篇文章中通过具体的代码来说明这个结论,并且会分析如果连接队列和半连接队列都满的话,内核会怎样处理。

首先来看半连接队列的上限是怎么计算和存储的。半连接队列长度的上限值存储在listen_sock结构的max_qlen_log成员中。如果找到监听套接字的sock实例,调用inet_csk()可以获取inet_connection_sock实例,inet_connection_sock结构是描述支持面向连接特性的描述块,其成员icsk_accept_queue是用来管理连接队列和半连接队列的结构,类型是request_sock_queue。listen_sock实例就存储在request_sock_queue结构的listen_opt成员中,它们之间的关系如下图所示(注:本来下面的图应该横着画,但是横着CSDN会显示不全):

Linux中listen()系统调用的backlog参数分析

半连接队列的长度上限在reqsk_queue_alloc()中计算并设置的,代码片段如下所示:

int reqsk_queue_alloc(struct request_sock_queue *queue,
        unsigned int nr_table_entries)
{
 .......
 
 nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog);
 nr_table_entries = max_t(u32, nr_table_entries, 8);
 nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);
 ......
 
 ......
 
 for (lopt->max_qlen_log = 3;
      (1 << lopt->max_qlen_log) < nr_table_entries;
      lopt->max_qlen_log++);
 
 ......

}

前面的三行代码是调整存储半连接的哈希表的大小,可以看到这个值还受系统配置sysctl_max_syn_backlog的影响,所以如果想调大监听套接字的半连接队列,除了增大listen()的backlog参数外,还需要调整sysctl_max_syn_backlog系统配置的值,这个配置量对应的proc文件为/proc/sys/net/ipv4/tcp_max_syn_backlog。后面的for循环是计算nr_table_entries以2为底的对数,计算的结果就存储在max_qlen_log成员中。

接着来看连接队列长度的上限,这个比较简单,存储在sock结构的sk_max_ack_backlog成员中,在inet_listen()中设置,如下所示:

int inet_listen(struct socket *sock, int backlog)
{
 ......
 
 sk->sk_max_ack_backlog = backlog;
 err = 0;

out:
 release_sock(sk);
 return err;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/30c2be731595075c8993b6af16dcaabb.html