TcpClient 的 NetworkStream 啥时候完成一次读操作?
Posted
技术标签:
【中文标题】TcpClient 的 NetworkStream 啥时候完成一次读操作?【英文标题】:When does TcpClient's NetworkStream finish one read operation?TcpClient 的 NetworkStream 什么时候完成一次读操作? 【发布时间】:2014-03-14 14:05:59 【问题描述】:我正在从事一个涉及通过 TCP 和 Google 协议缓冲区进行客户端服务器通信的项目。在客户端,我基本上是使用 NetworkStream.Read() 通过字节数组缓冲区从服务器进行阻塞读取。
根据 MSDN 文档,
该方法将数据读入buffer参数,返回成功读取的字节数。如果没有数据可供读取,Read 方法返回 0。Read 操作读取可用数据,最多为 size 参数指定的字节数。如果远程主机关闭连接,并且已接收到所有可用数据,则 Read 方法立即完成并返回零字节。
异步读取(NetworkStream.BeginRead 和 EndRead)也是如此。我的问题是 Read()/EndRead() 什么时候返回?似乎它会在缓冲区中的所有字节都被填充后返回。但在我自己的测试中,情况并非如此。在一个操作中读取的字节变化很大。我认为这是有道理的,因为如果在发送消息时服务器端出现暂停,客户端不应该等到读取缓冲区被填满。 Read()/EndRead() 本身是否有一些超时机制?
我试图找出 Mono 如何在 NetworkStream 中实现 Read() 并跟踪直到调用了外部方法 Receive_internal()。
【问题讨论】:
我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。 此外,这个问题与 C# 无关 - 这是一个 .NET 问题。 @JohnSaunders 感谢您的编辑。 如果 Read 正在等待一个完整的数据缓冲区,如果远程方期望您的响应但您正在等待一个永远不会到来的完整缓冲区,您很容易死锁。 @usr 是的,我理解那部分。但是当 Read() 返回时仍然假设缓冲区尚未满? 【参考方案1】:它读取网络流上或缓冲区已满时可用的所有数据。以先到者为准。您已经注意到了这种行为。
因此您需要处理所有字节并查看消息是否完整。您可以通过构建消息来做到这一点。请参阅 .NET question about asynchronous socket operations and message framing 了解如何执行此操作。
关于超时问题,如果假设你问 beginread 是否有超时,我会说没有,因为它只是在等待数据到达流并放入缓冲区,之后你可以处理传入的字节数。
读取操作中可用的字节数取决于您的网络(例如延迟、代理限制)和发送数据的客户端。
BeginRead 行为总结:
-
调用 BeginRead(); -> 等待字节到达流......
1 字节或更多字节已到达流中
开始将第 2 步中的字节放入给定的缓冲区中
调用 EndRead(); -> 缓冲区内的字节可由 EndRead() 处理;
最常见的做法是再次重复所有这些步骤。
【讨论】:
“它读取网络流上所有可用的数据”。因为networkstream是一个连续的流,你如何定义一个套接字读取操作的截止点(假设缓冲区太大以至于它永远不会被填满)?假设服务器每 50 毫秒发送一条消息(100 字节),那么在一次 NetworkStream.Read() 调用中客户端读取的字节数是多少? 正如“usr”下面的状态,“每次调用将返回一个字节和没有阻塞的可用字节数之间。没有什么,没有什么,没有其他保证。”这意味着它只会检查流上是否有数据。那是切入点。每次可用的字节数取决于您的网络(延迟、路由器等)和客户端等因素。【参考方案2】:如果 Read 正在等待一个完整的数据缓冲区,如果远程方期望您的响应但您正在等待一个永远不会到来的完整缓冲区,您很容易死锁。
根据这个逻辑,如果数据可用,它必须在没有阻塞的情况下返回。即使它只是一个可用的字节。
假设服务器每 50 毫秒发送一条消息(100 字节),那么在一次 NetworkStream.Read() 调用中客户端读取的字节数是多少?
每次调用都将返回一个字节和不阻塞可用的字节数之间。没有什么,没有什么,没有什么是可以保证的。在实践中,您将一次获得一个或多个网络数据包。堆栈保留可用字节是没有意义的。
【讨论】:
以上是关于TcpClient 的 NetworkStream 啥时候完成一次读操作?的主要内容,如果未能解决你的问题,请参考以下文章
为啥不读取 NetworkStream 中的数据? .net TcpClient