linux tcp三路握手详解

来源:互联网 发布:sql server 2005 教程 编辑:程序博客网 时间:2024/05/23 00:29

  特此声明:转载需要说明且附上本人链接!

  可能很多人都觉得自己懂tcp的三路握手,他知道那么三下子如下图。
    这里写图片描述
  但我更想问,你知道这些有个卵用。。。能排查出连接问题吗?可能你觉得用wireshark啊,tcpdump啊抓包能分析,但是你不了解协议栈怎么实现的,是很难做到良好的分析的。本文就告诉你,到底握手的过程中协议栈是怎么一步步处理的。

协议栈处理过程

 假设server的半连接和连接队列都是空的,过程如下。

  1. client向server发送【SYN】,状态为【SYN SENT】
  2. server收到client的【SYN】并回复【SYN+ACK】,这时候这个连接进入到server半连接队列,状态为【SYN RECEIVED】
  3. client收到server 【SYN+ACK】,回发【ACK】,client端认为三路握手成功,状态为【ESTABLISHED】
  4. server收到client的【ACK】,这时候这个连接就从server的半连接队列被转入已连接队列,server三路握手成功,状态为【ESTABLISHED】
  5. server调用了accept,这时候连接就从已连接队列移除了。

 这里就有几个问题了。比如server端已连接队列满了,server会怎么处理?半连接队列满了呢?又会怎么处理?以下就做一个说明。

  • 如果已连接队列满了,协议栈就会概率性地丢弃收到的SYN包,而对于不决定丢弃留下的SYN包,会回复SYN/ACK,但是之后收到的client回复的ACK会被丢弃,就等于没有收到ACK,进而server会有机制重发SYN/ACK,之后client收到之后就会认为原来我之前发的ACK server没收到啊,继续就会重发ACK。server直至超时都没有完成握手就发送RST,但如果超时时间内已连接队列有空间了并且收到了client的重试的ACK,那么就三路握手成功了。
  • 如果半连接队列满了呢?直接丢弃呗,还想啥。。
  • 三路握手和accept没关系,握手纯属协议栈的事。
  • 理论上只要server足够快地accept,那么backlog队列应该一直是”空”的,只有系统负载比较高的时候,才有必要用一个比较大的backlog值。
  • 只有在服务器和客户端之间的RTT特别大的时候,半连接队列才容易满;否则一般就是被DDOS攻击了。

趣事

  我之前做过这样的一个测试:server端listen(fd, 100),client拿着blocking的fd无限地连接,统计connect返回的成功连接的个数。
  这时候client发生了有趣的现象:前100多一点个连接一瞬间完成;之后统计的已连接数就开始慢慢悠悠的一个个增加。这是为什么呢?通过上面的陈述,你完全可以自己解决了。

趣题

  server端listen(fd, 100),但是server不调用accept,那么client和server双方视角下,成功连接了多少个?client的视角下成功多少个?

相关数目配置

  • 【连接队列】 个数为listen的backlog参数,但listen的再多也绝对不会超过somaxconn
  • 【半连接队列】个数为tcp_max_syn_backlog

参考链接

http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html

0 0
原创粉丝点击