[已解决,问题基于错误的假设]
在使用TCP时,我遇到了一个问题,NetworkStream.Read在两个不同的情况下返回值0,我很难区分。
一些背景知识 - 我有一个有效的客户端 - 服务器解决方案,通过TCP使用长度前缀消息进行通信。但是,由于大多数通信(除了一些初始消息交换)发生在客户端到服务器之间,因此服务器没有很好的方法来了解客户端是否仍然连接。找到这个的一种方法是不时向客户发送一些东西,这就是我决定做的事情。
我知道我可以添加专用的" ping"消息到我的协议,并在客户端中忽略它,但我也在测试其他可能性。我尝试的一件事是将空字节数组发送到客户端,如下所示:
networkStream.Write(new byte[0], 0, 0);
一切看起来都不错,它似乎在发送一个没有数据的TCP数据包......但是!我的客户端代码确实需要来自服务器的数据,因此它有一个在networkStream.Read上阻塞的线程,如下所示:
int bytesRead = networkStream.Read(buffer, 0, 4);
if (bytesRead == 0)
break;
根据文档,如果另一端关闭连接,Socket.Read(或NetworkStream.Read)将返回0。这是事实,但在我的情况下,在发送空字节数组后,Read(...)也返回0。
到目前为止,我无法区分这两种情况。在两种情况下(连接关闭和空字节数组),在Read为 true 之后检查Socket.Connected。还有其他方法可以解决这个问题吗?
同样,我知道发送这个空数组几乎与为此目的添加新类型的消息相同。我不是在这里要求解决方案...只是想知道.NET的Socket是否可以区分空字节数组和连接关闭。
编辑: 我很抱歉打扰每个人一个问题,最终是基于不正确的假设。我的测试没有在我的生产代码上完成,而且太过于草率。这导致我得出不正确的结论。 基本上,我测试的是如果我在一端写一个Write(新字节[0] ...),另一端的Read(...)将返回0.它确实,但不是由于发送。我用来测试的TcpClient超出了范围,这(我假设)导致它被GC处理,因此连接关闭,导致Read返回0.我确实重复测试TcpClient没有被处理/无论我发送了多少个空字节数组,Read都不会返回任何内容。
起初,我希望Nagle的算法搞砸了,但在这种情况下它并没有 - 因为我在localhost上测试,1字节数组没有延迟。我可以使用套接字进行不同的测试,并明确禁用Nagle的算法,但我不认为这会改变任何东西。
现在我只需要检查发送这样一个数组是否实际上允许我检测到断开连接,但这是一个不同的故事,而不是在这个问题的范围内。
编辑2: 我做了一些关于此的测试,并发现,尽管有一些建议,例如here(这似乎是一个有效的信息来源),做空发送不能识别断开的连接。我物理断开了网络电缆,我的服务器每5秒做一次空的发送。它已经好几分钟了,没有检测到断线。如果我决定发送任何数据(甚至是单个字节),最多会在20秒后检测到断开连接。
答案 0 :(得分:3)
来自MSDN的NetworkStream.Read Method (Byte[], Int32, Int32):
Read操作读取尽可能多的数据,直到 size参数指定的字节数。如果没有数据 可用于读取,Read方法返回0。
在发送数据时,您发送一个空字节数组并使用以下方法写入零字节:
networkStream.Write(new byte[0], 0, 0);
然而,在阅读数据时,您声称
- “我的客户端代码确实需要来自服务器的数据,所以 它有一个在networkStream上阻塞的线程。“
醇>
int bytesRead = networkStream.Read(buffer, 0, 4);
if (bytesRead == 0)
break;
但是,然后再次尝试将4个字节读取到字节数组,这显然会继续等待。那么,你还期待什么呢?
- “...只是想知道.NET的Socket是否可以区分空 字节数组和连接关闭。“
醇>
连接关闭完全是另一回事,在关闭Socket连接之前需要几个步骤。所以,显然,它与发送或接收零字节不同!
- >最后,正如@WithMetta在评论中暗示的那样,请使用NetworkStream.DataAvailable Property
检查数据是否可供阅读。
while(networkStream.DataAvailable) { // your code logic}