[已解决,该问题基于错误的假设]
在使用 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 后检查 Socket.Connectedtrue在这两种情况下(连接关闭和空字节数组)。还有其他方法可以处理这个问题吗?
再说一次,我确实知道发送这个空数组几乎与为此目的添加新类型的消息相同。我不是在这里寻求解决方案...只是想知道.NET 的 Socket 是否可以区分空字节数组和连接关闭。
编辑:
我很抱歉用一个问题打扰大家,这个问题最终是基于错误的假设。我的测试没有在我的生产代码上完成,而且太草率了。这导致我得出了错误的结论。
基本上,我正在测试的是,如果我在一端执行 Write(new byte[0]...) ,另一端的 Read(...) 将返回 0。确实如此,但不是由于发送所致。我用来测试的 TcpClient 超出了范围,这(我假设)导致它被 GC 处理,因此连接被关闭,这导致 Read 返回 0。我确实重复了测试,但 TcpClient 没有被处理/丢失,并且读取不会返回任何内容,无论我发送多少个空字节数组。
起初,我预计 Nagle 的算法会把事情搞砸,但在本例中却没有——1 字节数组毫无延迟地到达,正如我在 localhost 上进行的测试一样。我可能会使用套接字进行不同的测试,并显式禁用 Nagle 算法,但我认为这不会改变任何事情。
现在我只需要检查发送这样的数组是否真的能让我检测到断开连接,但这是一个不同的故事,不在这个问题的范围内。
编辑2:
我对此做了更多测试,发现尽管有一些建议,例如here https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx(这似乎是一个有效的信息来源),执行空发送无法识别断开的连接。我物理上断开了网络电缆,并且我的服务器每 5 秒执行一次空发送。这样持续了几分钟,没有检测到断线。如果我决定发送任何数据(即使是一个字节),最多 20 秒后就会检测到断开连接。