众所周知,MTU为1500,TCP的MSS为1460.因此,当recv函数中使用的buf大于1460字节时,TCP将被分成许多部分。
我编写了一个简单的echo prog,并希望使用tcpdump来检查碎片。但是,当buf很小时它没有显示碎片,但是当buf大约是20K时显示。以下是代码:
服务器:
import socket
import sys
import os
addr = ('10.0.0.2',10086)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(addr)
server.listen(5)
while True:
connfd, addr= server.accept()
print 'connection ip:', addr
data = connfd.recv(8192);
客户端:
import socket
import os
import sys
addr = ('10.0.0.2', 10086)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(addr)
data = '';
for num in range(0,8192):
data += '1'
client.sendall(bytes(data))
这是我使用的tcpdump cmd:
sudo tcpdump -i lo port 10086 -s 1514 -v
从代码中看,buf是8192,MSS是1460.所以,在我看来,数据包将分为1460,1460,1460,1460,1460,892。但是在屏幕截图中没有。
另外,我不确定这是否是由[DF]标志引起的。编程使用python,所以内置sockopt [DF]默认设置?天知道。
答案 0 :(得分:4)
众所周知,MTU为1500,TCP的MSS为1460
事实并非如此。
MTU取决于传输介质,1500的MTU特定于以太网。但是基于你的tcpdump,你没有使用以太网接口(即两台机器之间的有线局域网连接),但在同一台机器上有客户端和服务器,因此使用lo
接口(tcpdump -i lo ...
)。 localhost接口的MTU通常要高得多:
$ ifconfig lo
lo: ... mtu 65536
$ ifconfig eth0
eth0: ... mtu 1500
除此之外,你可能根本看不到任何碎片。如果数据包大于MTU,您将看到TCP分段(不是分段),即OS将TCP流分成不同的段,其中每个段不大于MSS。而是在较低层上发生分段,例如,如果需要进一步拆分IP分组,因为到目标的路径中的某个地方是具有较小MTU的设备。
您看到的[DF]
(不分段)是为了确保不会发生IP级别碎片,而是丢弃数据包并通知发送方,以便路径MTU(路径的最小MTU)可以被发现并为此优化TCP分段,以减少交付的开销。有关详细信息,请参阅Path MTU discovery。
答案 1 :(得分:2)
我想补充一点,您不会看到带有 tcpdump 过滤器的片段,因为您正在过滤端口号。 IP 片段实际上没有端口号。只是数据包 ID 和偏移量以及协议号。因此,您应该使用 IP src 或目标对 UDP 进行过滤。 或使用此过滤器查看片段: tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'
信用:https://github.com/SergK/cheatsheat-tcpdump/blob/master/tcpdump_advanced_filters.txt
答案 2 :(得分:1)
您正在一台主机内从localhost向localhost发送数据。 因此,以太网(1500)的MTU不会限制MSS的大小,因为数据不会通过以太网。
尝试在两个不同的主机之间重复测试。