【发布时间】:2024-01-20 13:40:01
【问题描述】:
[已解决,问题基于不正确的假设]
在使用 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。
到目前为止,我无法区分这两种情况。在这两种情况下(连接关闭和空字节数组),读取后检查的 Socket.Connected 为 true。有没有其他方法可以解决这个问题?
再一次,我知道发送这个空数组几乎与为此添加新类型的消息相同。我不是在这里寻求解决方案...只是想知道 .NET 的 Socket 是否可以区分空字节数组和连接关闭。
编辑: 我很抱歉用一个问题打扰大家,这最终是基于错误的假设。我的测试没有在我的生产代码上完成,而且太草率了。这导致我得出错误的结论。 基本上,我正在测试的是,如果我在一端执行 Write(new byte[0]...),另一端的 Read(...) 将返回 0。确实如此,但不是由于发送。我用来测试的 TcpClient 超出了范围,这(我假设)导致它被 GC 释放,因此连接关闭,导致读取返回 0。我确实重复了测试,但 TcpClient 没有被释放/丢失,并且无论我发送多少个空字节数组,Read 都不会返回任何内容。
起初,我预计 Nagle 的算法会搞砸,但在这种情况下并非如此 - 1 字节数组会毫无延迟地到达,因为我在 localhost 上进行测试。我可能会使用套接字进行不同的测试,并明确禁用 Nagle 的算法,但我认为这不会改变任何事情。
现在我只需要检查发送这样一个数组是否真的可以让我检测到断开连接,但这是另一回事,不在这个问题的范围内。
编辑 2: 我对此进行了更多测试,并发现尽管有一些建议,例如here(这似乎是一个有效的信息来源),执行空发送不会识别断开的连接。我物理上断开了网络电缆,我的服务器每 5 秒进行一次空发送。就这样持续了几分钟,没有检测到断线。如果我决定发送任何数据(甚至是单个字节),最多会在 20 秒后检测到断开连接。
【问题讨论】:
-
也许这篇文章会有所帮助social.msdn.microsoft.com/Forums/en-US/…
-
答案说“当对等套接字关闭时,对 Read 的调用应该只返回零字节”,这是不正确的......我可以让 Read 返回 0 字节而不关闭连接,因此问题
-
也许尝试在第一篇文章中使用 do{ } while (stream.DataAvailable) 而不是中断 0 字节。
-
@MarcinPawlica - 我确信代码存在问题,您没有在此处显示。这就是为什么每个人都要求海报制作一个显示实际问题的 MCVE。下次请多多关照……
标签: c# .net sockets tcp network-programming