C# NetworkStream - 在读取时区分关闭套接字和 0 字节数组

2024-03-24

[已解决,该问题基于错误的假设]

在使用 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 秒后就会检测到断开连接。


来自 MSDN 的NetworkStream.Read 方法 (Byte[], Int32, Int32) https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read(v=vs.110).aspx:

读取操作读取尽可能多的可用数据,最多可达 由 size 参数指定的字节数。如果没有数据 可供读取,Read 方法返回 0。


发送数据时,您将发送一个空字节数组并使用以下命令写入零字节:

networkStream.Write(new byte[0], 0, 0);

然而,在阅读数据时,您声称

  1. “我的客户端代码确实不时需要来自服务器的数据,所以 它有一个线程阻塞在networkStream上。”
int bytesRead = networkStream.Read(buffer, 0, 4);
if (bytesRead == 0)
   break;

但是,您再次尝试将 4 个字节读取到字节数组中,这显然会继续等待。那么,你还期待什么呢!

  1. “...只是想知道.NET 的 Socket 是否可以区分空的 字节数组和连接关闭。”

连接关闭完全是另一回事,它涉及关闭 Socket 连接之前的几个步骤。所以,显然,它与发送或接收零字节不同!

-> 最后,正如@WithMetta在评论中所暗示的,请检查数据是否可以读取或不使用NetworkStream.DataAvailable Property https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.dataavailable(v=vs.110).aspx.

while(networkStream.DataAvailable) { // your code logic}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# NetworkStream - 在读取时区分关闭套接字和 0 字节数组 的相关文章

随机推荐