你好,游客 登录 注册 搜索
背景:
阅读新闻

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

[日期:2013-02-23] 来源:Linux社区  作者:moonvs2010 [字体: ]

在启动测试程序之前,在客户端使用tcpdump抓包,并将输出结果通过-w选项存储在192.cap文件中,便于后续使用wireshark来分析。

测试发现,在客户端建立300个连接后,客户端建立连接的速度明显慢了很多,而且最终建立完1000个连接花了20分钟左右。使用wireshark打开192.cap文件,来看抓包的情况,发现在300个连接之后有大量的ack包重传,如下图所示:

在wireshark的过滤器中选择本地端口为49274的连接来具体分析,该连接抓包情况如下所示:

上面的图中可以看到,SYN包重传了一次;在正常的三次握手之后,服务器又发送了SYN+ACK包给客户端,导致客户段再次发送ACK,而且这个过程重复了5次。在wireshark中过滤其他连接,发现情况也是如此。

问题来了,为什么要重传SYN包?为什么在三次握手之后,服务器端还要重复发送SYN+ACK包?为什么重复了5次之后就不再发了呢?要解答这些问题,我们需要深入到内核代码中看三次握手过程中内核是如何处理的,以及在连接队列满之后是怎么处理。内核中处理客户端发送的SYN包是在tcp_v4_conn_request()函数中,关键代码如下所示:

int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
 ......

 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
#ifdef CONFIG_SYN_COOKIES
  if (sysctl_tcp_syncookies) {
   want_cookie = 1;
  } else
#endif
  goto drop;
 }

 /* Accept backlog is full. If we have already queued enough
  * of warm entries in syn queue, drop request. It is better than
  * clogging syn queue with openreqs with exponentially increasing
  * timeout.
  */
 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
  goto drop;

 req = inet_reqsk_alloc(&tcp_request_sock_ops);
 if (!req)
  goto drop;                 ......                   
 if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
  goto drop_and_free;

 inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
 return 0;

drop_and_release:
 dst_release(dst);
drop_and_free:
 reqsk_free(req);
drop:
 return 0;
}

linux
相关资讯       Linux系统调用  listen调用backlog  Linux listen 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款