歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux中listen()系統調用的backlog參數分析

這篇文章是對上一篇博客網絡編程常用接口的內核實現----sys_listen()的補充(見 http://www.linuxidc.com/Linux/2013-02/79858.htm ),上篇文章中我說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會顯示不全):

半連接隊列的長度上限在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;
}

Copyright © Linux教程網 All Rights Reserved