我设置了一个简单的客户端服务器,似乎我从客户端发送的 TCP 数据包没有到达服务器。
通常一切正常,但是当我在客户端上启动 50 个线程以使用相同的小数据包(只有 39 个字节)“同时”访问服务器时,服务器没有收到所有字节的随机次数。更奇怪的是,它不接收它们的方式非常一致……只接收到 5 个字节。
我正在使用tcpdump和tcpflow来捕获两端发生的事情(如果不熟悉 tcp 流,它会从 TCP 流中消除大量的 TCP SYN/ACK/FIN/etc 噪声,并且只显示发送的数据任一方向)。
在客户端,对于 50 个线程触发 39 字节数据包,它看起来很完美。具体来说,tcpflow(使用 libpcap)向我展示了 50 个相同的数据传输:
07 B6 00 01 | 00 1E 00 00 | <etc>
据我了解,libpcap/tcpdump 从相当低的级别(低于 TCP 堆栈)获取数据,所以我认为这意味着数据发送正常,或者至少没有卡在内核缓冲区中。
但是,在查看服务器端时,一切都不是完美的。随机数失败,而且百分比很高。例如,在 50 个套接字连接中,有 30 个可以正常工作,但是对于其中的 20 个,我遇到了协议故障,服务器socket.recv
超时等待字节(协议指示确切的数据包长度)。
它的失败方式非常一致。对于 30/20 的情况,30 个套接字完全接收传输的 39 个字节。剩下的 20 人都收到了这部分数据,之后我的socket.recv
超时:
07 B6 00 01 | 00
20 个连接中的每一个只有 5 个字节到达,而且它似乎在内核级别,因为 tcpdump 也只显示 5 个字节到达。
这怎么可能发生?
这个 5 字节的边界并不是 100% 的巧合。它是报头的第一部分,接下来是 34 字节的有效负载,但没有到达。在客户端,它是这样拆分的。
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.sendall(HEADER) # 5 bytes
sock.sendall(PAYLOAD) #34 bytes
并且两个sock.sendall
调用在每个线程中都成功完成,正如我的 tcp 日志记录所证明的那样,所有 50 次运行都完美地“发送”了 39 个字节。
关于这个根本原因的任何想法?我错过了什么?