Networkstream.Write() 阻塞问题
我目前正在测试我编写的托管 c# 网络库,并且偶尔遇到问题。此问题表现为在所有发送操作中可能有 1% 的 networkstream.write() 上出现非常一致(始终在 30 毫秒内)的 5000 毫秒阻塞。这是在测试环境中,全部在本地运行,每次都使用完全相同的数据包大小 (2MB)。在客户端,我不断地将以下内容写入连接的网络流:
tcpClientNetworkStream.Write(headerBytes, 0, headerBytes.Length);
tcpClientNetworkStream.Write(dataBytes, 0, dataBytes.Length);
在服务器端,我使用异步读取等待数据。一旦出现数据,我就会在 tcpClientNetworkStream.DataAvailable 上使用 while 循环,直到收到所有数据。
我知道如果缓冲区已满,networkstream.write() 可能会阻塞,但如果这是问题,我想不出在服务器端清除它们的更快方法(发送和接收缓冲区大小默认为 8192 字节) 。事实上,这个区块如此一致似乎很奇怪。我的第一个想法可能是某种形式的 Thread.Sleep,但进行完整的项目搜索后却没有发现任何形式。如果有人能帮助阐明这个问题,我们将不胜感激。
马克
编辑添加:似乎可以使问题消失的黑客如下(尽管由于BlockCopy而导致相关的性能下降):
byte[] bytesToSend = new byte[headerBytes.Length + dataBytes.Length];
Buffer.BlockCopy(headerBytes, 0, bytesToSend, 0, headerBytes.Length);
Buffer.BlockCopy(dataBytes, 0, bytesToSend, headerBytes.Length, dataBytes.Length);
tcpClientNetworkStream.Write(bytesToSend, 0, bytesToSend.Length);
编辑添加2:我还通过使用两个异步写入来重现该问题两者之间的线程信号。目前我唯一的解决方案是上面编辑中的单个写入操作。
编辑添加3:好的,另一个可能的修复如下。我仍然有兴趣知道为什么连续写入偶尔会以这种方式“阻塞”。
BufferedStream sendStream = new BufferedStream(tcpClientNetworkStream);
sendStream.Write(bytesToSend, 0, bytesToSend.Length);
sendStream.Write(packet.PacketData, 0, packet.PacketData.Length);
sendStream.Flush();
编辑到add4:经过进一步广泛的测试,“编辑到add3”中的解决方案并没有使问题消失,它只是将发送的发生率减少到大约0.1%。好多了,但还远未解决。接下来我将用阻塞读取替换异步读取,看看是否可以按照 PaulF 的建议对其进行排序。
I'm currently testing a managed c# network library I've written and I've come up against an occasional problem. This problem manifests as a very consistent (always within 30ms) 5000ms block on networkstream.write() for perhaps 1% of all send operations. This is in a test environment, all running locally, using the exact same packet size (2MB) each time. On the client end I continuously write the following to a connected networkstream:
tcpClientNetworkStream.Write(headerBytes, 0, headerBytes.Length);
tcpClientNetworkStream.Write(dataBytes, 0, dataBytes.Length);
and on the server end I use an asynchronous read waiting for data. Once data appears I use a while loop over tcpClientNetworkStream.DataAvailable until all data has been received.
I am aware that networkstream.write() can block if the buffers are full but if this is the problem I can't think of a quicker way of clearing them at the server end (Send and Receive buffer sizes are default at 8192 bytes). The fact the block is so consistent seems very odd. My first thought was possibly some form of Thread.Sleep but doing a full project search shows none. If anyone could help shed some light on this issue that would be greatly appreciated.
Marc
edit to add: A hack which seems to make the problem go away is the following (although there is an associated performance hit due to the BlockCopy):
byte[] bytesToSend = new byte[headerBytes.Length + dataBytes.Length];
Buffer.BlockCopy(headerBytes, 0, bytesToSend, 0, headerBytes.Length);
Buffer.BlockCopy(dataBytes, 0, bytesToSend, headerBytes.Length, dataBytes.Length);
tcpClientNetworkStream.Write(bytesToSend, 0, bytesToSend.Length);
edit to add2: I've also reproduced the problem by using two asynchronous writes with a thread signal between the two. At the moment the only solution I have is the single write operation as in the above edit.
edit to add3: Ok, another possible fix follows. I'm still interested to know why the successive write occasionally 'blocks' in the way it does.
BufferedStream sendStream = new BufferedStream(tcpClientNetworkStream);
sendStream.Write(bytesToSend, 0, bytesToSend.Length);
sendStream.Write(packet.PacketData, 0, packet.PacketData.Length);
sendStream.Flush();
edit to add4: After further extensive testing the solution in 'edit to add3' does not make the problem go away, it just reduces the occurrence to about 0.1% of sends. Much better but far from solved. I will be replacing the asynchronous read with a blocking read next to see if that sorts it, as suggested by PaulF.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,这个问题没有具体的答案,所以我会尽力自己提供一个小结论。我最好的猜测是,这个问题最初是因为我填充 tcp 缓冲区的速度比清除它的速度快而引起的。如果缓冲区已满,则在尝试添加更多数据之前会有一些未知的等待时间。当在同一台机器内发送和接收数据时,这个问题可能最为明显。重要的是要记住,.net 中的默认读取缓冲区大小仅为 8192 字节,因此如果写入更大的块,也许可以考虑将此读取缓冲区大小增加到更大的值,例如 512000 字节。然而,由于大对象堆等,这本身会导致其他问题,但这可能是对不同问题的讨论。
Ok, no specific answers to this question so I will do my best to provide a little conclusion myself. My best guess is that this problem was originally caused because I was filling the tcp buffer faster than I was clearing it. If the buffer is filled there is some unknown wait time before attempting to add more data. This problem would perhaps be most apparent when sending and receiving data within the same machine. It's important to remember that the default read buffer size in .net is only 8192 bytes, so if writing in much larger chunks, perhaps consider increasing this read buffer size to something larger such as 512000 bytes. However this in itself causes other issues due to the large object heap etc but that is potentially discussion to a different question.