奇怪的 send() 问题(带有 Wireshark 日志)
关于这个问题我还有一个问题,但是我没问好,所以我又来了!
我正在通过分块发送文件的方式发送文件。现在,我正在尝试使用不同的数字来确定该块的大小,看看什么大小最有效。
在本地主机上测试时,任何块大小似乎都可以正常工作。但是当我通过网络测试它时,最大块大小似乎是 8191 字节。如果我尝试更高的速度,传输就会变得非常、痛苦、缓慢。
为了显示发生的情况,以下是当我使用 8191 字节的块大小和使用 8192 字节的块大小时 Wireshark 日志的前 100 行:(发送方为 192.168.0.102,接收方为 192.168.0.100 )
8191:http://pastebin.com/E7jFFY4p
8192:http://pastebin.com/9P2rYa1p
请注意,在 8192 日志的第 33 行中,接收方如何花费很长时间来 ACK 数据。这种情况在第 103 行和第 132 行再次发生。我相信这种延迟是问题的根源。
请注意,我没有修改 SO_SNDBUF 选项或 TCP_NODELAY 选项。
所以我的问题是,为什么在以 8192 字节块发送文件时会收到延迟的 ACK,而在使用 8191 字节块时一切正常?
I had another question about this issue, but I didn't ask properly, so here I go again!
I'm sending a file by sending it in chunks. Right now, I'm playing around with different numbers for the size of that chunk, to see what size is the most efficient.
When testing on the localhost, any chunk size seems to work fine. But when I tested it over the network, it seems like the maximum chunk size is 8191 bytes. If I try anything higher, the transfer becomes extremely, painfully, slow.
To show what happens, here are the first 100 lines of Wireshark logs when I use a chunk size of 8191 bytes, and when I use a chunk size of 8192 bytes: (the sender is 192.168.0.102, and the receiver is 192.168.0.100)
8191: http://pastebin.com/E7jFFY4p
8192: http://pastebin.com/9P2rYa1p
Notice how in the 8192 log, on line 33, the receiver takes a long time to ACK the data. This happens again on line 103 and line 132. I believe this delay is the root of the problem.
Note that I have not modified the SO_SNDBUF option nor the TCP_NODELAY option.
So my question is, why am I getting delayed ACKs when sending files in chunks of 8192 bytes, when everything works fine when using chunks of 8191 bytes?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想通了!首先是我自己,然后经过更多挖掘,我发现了这一点:
http://support.microsoft.com/kb/823764
实际发生的情况是因为Winsock 分配的发送缓冲区默认情况下(在我的机器上)正好是 8192 字节,当我将这个字节数放入缓冲区时(实际上完全填满它),下一个 send() 将给出 WSAEWOULDBLOCK。然后,只有在字节被确认后,我才会收到下一个 FD_WRITE。
但与此同时,由于 ACK 算法延迟,接收机器没有发送 ACK。这使传输陷入 200 毫秒的死锁,之后接收机器最终确认数据,然后允许发送函数接收 FD_WRITE。
当然,当我使用 8191 字节时,这一切都不会发生,因为我没有填满整个缓冲区,因此下一个 send() 不会阻塞。这意味着 Winsock 将始终保持发送数据,以便延迟 ACK 算法永远不会在接收端启动(如果最后一个数据包是奇数数据包,则除外)。
希望这可以帮助其他遇到我遇到同样问题的人。
I figured it out! First by myself, and then after some more digging, I found this:
http://support.microsoft.com/kb/823764
What was actually happening is that because the send buffer allocated by Winsock is by default (on my machine) exactly 8192 bytes, when I put that amount of bytes in the buffer (effectively completely filling it up), the next send() will give WSAEWOULDBLOCK. Then, I would only receive the next FD_WRITE once the bytes have been ACKed.
But at the same time, the receiving machine was not sending an ACK because of the delayed ACK algorithm. This put the transmission into a deadlock for 200 ms, after which the receiving machine finally ACKs the data, which then allows the send function to receive an FD_WRITE.
Of course, all this does not happen when I used 8191 bytes because I did not fill up the whole buffer, and thus the next send() did not block. This meant that Winsock would always keep sending data so that the delayed ACK algorithm never kicked in on the receiving end (except on the last packet if it is an odd-numbered packet).
Hope this helps anyone else with the same issue I had.
检查 NIC 和交换机上的“流量控制”设置。如果它打开,则可能是导致您出现问题的原因。
为了正确解剖,您需要在传输的两端运行wireshark。
Check your "Flow Control" setting on your NICs and switches. If it is on, it may be the cause of your problem.
And for proper dissection you will need to run wireshark on both ends of the transfer.