TCP三次握手的第三个ack丢了会怎样

这个是在网上看到的面试题,引用下原文的内容

当Client端收到Server的SYN+ACK应答后,其状态变为ESTABLISHED,并发送ACK包给Server;
 
如果此时ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且依次等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包,以便Client重新发送ACK包。
           
Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5。
             
如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server自动关闭这个连接。

但是Client认为这个连接已经建立,如果Client端向Server写数据,Server端将以RST包响应,方能感知到Server的错误。

嗯。前面都没问题,就是最后一个,client和server段的处理,我很疑惑。

  1. tcp是累加ack,而且ack在tcp包头,也就是所有tcp包都应该带有ack数据,中间丢一个纯ack包,不应该影响tcp通讯
  2. 第三个握手包只关乎是否已经收到第二个握手的syn包,所以只要后面带数据的ack,能ack到syn包,应该没问题
  3. 好像也没在哪里看到说不准在第三个ack里面发数据啊?这个我不确定,有知道的ping我一下

不确定的时候就想到了做实验。那么怎么做呢?

linux tc命令

嗯,模拟网络丢包,本来我想用vmware的丢包模拟的,结果我发现要fusion10 pro才有这个feature,我买的不是pro。。。。好吧,我又找到了tc命令。这个命令的netem模块能模拟网络丢包的情形,但只能控制流出的包。所以我起来两个Linux机器,一个跑server,一个跑client。server是一个简单的socket程序,接到连接之后打印一个success,读一下数据,然后close。client就连上之后,发一个hello,然后close。

具体的丢包模拟命令为

sudo tc qdisc add dev eth0 root netem loss 30%

在client机器上跑这个命令,这样就可以模拟30%丢包率的情况了(本来我用了50%的概率测试的,结果我发现大概率连第一个syn包都发不出来,降低到30%,就比较合适了)

测试结果

在服务器抓包,看起来,至少在ubuntu12.04上面,服务器端是不会发rst的:


可以看到131和132号包,是两个握手包,133号包,len为7,已经携带数据,服务器并没有发rst。由于我的测试程序发完数据就close,所以马上客户端就开始发fin了。而服务器也能正确close这个连接。

TCP Fast Open

这个选项与上面的讨论没有直接关系,只是额外发现的一个补充。

在linux上面有选项

/proc/sys/net/ipv4/tcp_fastopen

用以控制是否允许快速打开。默认为1

该功能的行为是,第一个握手包会带一个cookie和应用数据,服务器收到syn之后,如果cookie正确,允许服务器直接开始返回数据,而不需要等第三个ack。如果syn不正确,客户端需要在第三个ack的时候重新携带数据。当然这个需要服务器客户端同时配合。

可见握手是不是携带数据并不是一定的,携带数据,是不是会被rst,实际上有点看具体tcp ip栈的实现,我相信肯定有坑爹的tcp实现会在这个时候rst的,特别是嵌入式领域。

猜你喜欢

转载自blog.csdn.net/zerooffdate/article/details/79359726