0%

说好再见要挥手四次呢

计算机网络教材里,都是说TCP连接会经过三次握手,而断开的时候会进行四次挥手

但是在实际的应用场景,为什么我在tcpdump抓的包里发现,挥手只有三次呢?

从上图可以看到,这一条TCP流断开的过程中,首先是80端口的HTTP服务器向客户端发送了FIN标志位,然后客户端返回FIN ACK标志位,然后服务器返回ACK后,这条TCP流就没有后续的操作了。

从TCPDUMP的结果来看,数据包经过的流程如下

sequenceDiagram;
participant a as HTTP服务器
participant b as 客户端

a->>b: FIN
b->>a: FIN,ACK
a->>b: ACK

来回数据包总共只有三个,是教科书出错了吗?

其实并不是教科书错了,而是在实际应用场景里,TCP有一项为了效率的功能发挥了作用。

现代TCP/IP协议分为5层,应用数据从上而下传输时,会在数据前方添加各层级的数据包头

最常见的以太网V2 MAC层包头长度14字节,MAC尾部FCS占用4字节,IP层的数据包头占用20个字节,TCP不考虑可选扩展部分,也是占用20字节。
54字节

而ACK字段在TCP首部的flag信息里,如果只回应ACK不传输数据的话,在网络上传输的数据字节流是58字节,实际应用部分数据为0字节,这样的话效率就非常低,有效载荷为0%,而如果在有数据的情况传输,假设有100字节的应用层数据需要传输,那么总共传输的字节就是158字节,但是有效载荷达到了66.67%。

而如果我们假定MTU最大传输单元是1500字节,应用层数据有1442字节时,字节流就达到了MTU上限,此时的有效载荷达到了96.13%。

为了让传输效率尽可能高,就要尽可能避免只传输TCP flags的情况,最好时传输的时候能够有应用层的数据载荷。因此,在TCPIP内核协议栈里,有一个功能,叫做TCP延迟确认(TCP delayed acknowledgment),这个机制可以让ACK确认报文延迟发送,减少协议开销。在RFC1122规范里定义,一个主机至多可以延迟500ms再发送ACK报文。

回到刚刚的应用场景,HTTP服务器向客户端发起断开,而客户端也没有继续传向服务器的数据,因此由于TCP延迟确认机制的作用,ACK确认报文被延后与FIN一起发送,由此,四次挥手变成了看起来的三次挥手。


TCP延迟确认机制可以增加传输效率,让数据传输过程中的有效载荷尽可能高。

那么这个机制有没有缺点呢?

在我看来,至少这个机制,会影响到数据传输过程中的延迟性能,由于ACK确认报文回包的慢了,可能会让后续数据的传输也被延后。

所以,要根据实际的应用场景,来决定是否要开启TCP延迟确认机制。假如在家里,有WiFi的情况下,关闭这个机制,是不是上网浏览体验会更好呢?