iperf3或TCP协议栈合并TCP数据包的原因及Ubuntu 22.04下的关闭方法
嘿,这个现象其实是TCP协议栈里的Nagle算法和**延迟确认(Delayed ACK)**在联手搞事情,咱们来捋清楚:
为什么会出现数据包合并?
Nagle算法:这是TCP默认开启的拥塞优化机制,目的是避免网络被大量小数据包塞满(也就是所谓的"小分组风暴")。它的逻辑是:如果当前还有未被确认的小数据包,就会把后续的小数据包暂存在发送缓冲区里,要么等攒到接近MTU的大小,要么等收到之前数据包的ACK后再一起发送。你用
iperf3 -l 100指定了每个应用层报文是100字节,但内核的TCP栈会因为Nagle算法把多个100字节的报文合并成一个大包发送。延迟确认:接收方(这里是iperf3的服务端)默认不会收到数据包就立刻回复ACK,而是会等待一小段时间(通常200ms以内),要么攒够两个ACK一起发,要么等自己有数据要发送时捎带ACK。这会反过来让发送方的Nagle算法有更多时间攒小数据包,最终形成更大的合并包。
Ubuntu 22.04下怎么关闭这种合并?
你可以通过调整TCP内核参数来禁用这些机制,分临时生效和永久生效两种方式:
1. 禁用Nagle算法
Nagle算法对应的内核参数是tcp_nodelay,开启它(值为1)就会禁用Nagle,让每个小数据包立即发送:
- 临时生效(重启后失效):
sudo sysctl -w net.ipv4.tcp_nodelay=1 - 永久生效:
编辑/etc/sysctl.conf文件,添加或修改一行:
然后执行net.ipv4.tcp_nodelay=1sudo sysctl -p让配置生效。
2. 禁用延迟确认
延迟确认对应的参数是tcp_delack_min,把它设为1会让接收方立即回复ACK:
- 临时生效:
sudo sysctl -w net.ipv4.tcp_delack_min=1 - 永久生效:
同样在/etc/sysctl.conf里添加:
再执行net.ipv4.tcp_delack_min=1sudo sysctl -p生效。
3. 针对环回接口的额外注意
因为你用的是localhost(环回接口lo),不过环回接口的TCP参数和系统全局参数是一致的,上面的设置已经会生效,不需要单独配置接口参数。
验证效果
修改完参数后,重新运行你的iperf3命令和tcpdump:
iperf3 -c localhost --time 1 -l 100 --bitrate 100M
sudo tcpdump -i lo -B 10000000 tcp port 5201
这时候你应该会看到所有数据包都是100字节的长度了。
备注:内容来源于stack exchange,提问作者Ken Y-N

