TcpClient的NetworkStream何时完成一次读操作?

时间:2014-02-15 02:00:14

标签: c# sockets tcp mono networkstream

我正在开发一个涉及通过TCP和Google协议缓冲区进行客户端服务器通信的项目。在客户端,我基本上使用NetworkStream.Read()通过字节数组缓冲区从服务器进行阻塞读取。

根据MSDN文档,

  

此方法将数据读入buffer参数并返回成功读取的字节数。如果没有可用于读取的数据,则Read方法返回0. Read操作读取尽可能多的数据,直到size参数指定的字节数。如果远程主机关闭连接,并且已收到所有可用数据,则Read方法立即完成并返回零字节。

与异步读取(NetworkStream.BeginRead和EndRead)的情况相同。我的问题是Read()/ EndRead()何时返回?看起来它会在填充缓冲区中的所有字节后返回。但在我自己的测试中,情况并非如此。在一次操作中读取的字节变化很大。我认为这是有道理的,因为如果在发送消息时服务器端有暂停,客户端不应该等到读取缓冲区已经填满。 Read()/ EndRead()本身是否有一些超时机制?

我试图找出Mono如何在NetworkStream中实现Read()并跟踪,直到调用extern方法Receive_internal()。

2 个答案:

答案 0 :(得分:2)

它读取网络流上或缓冲区已满时可用的所有数据。以先到者为准。您已经注意到了这种行为。

因此,您需要处理所有字节并查看消息是否完整。您可以通过构建消息来完成此操作。请参阅.NET question about asynchronous socket operations and message framing,了解如何执行此操作。

至于超时问题,如果假设你在询问beginread是否有超时,我会说不,因为它只是等待数据到达流并将其放入缓冲区,之后你可以处理传入的字节。

读取操作中可用的字节数取决于网络(例如延迟,代理限制)和发送数据的客户端之类的内容。

BeginRead行为摘要:

  1. 调用BeginRead(); - >等待字节到达流......
  2. 1个字节或更多已到达流
  3. 开始将步骤2中的字节放入已给出的缓冲区
  4. 调用EndRead(); - >缓冲区内的字节可以由EndRead();
  5. 处理
  6. 最常见的做法是再次重复所有这些步骤。

答案 1 :(得分:1)

如果Read等待完整的数据缓冲区,如果远程方期望你的响应但你正在等待一个永远不会出现的完整缓冲区,你很容易陷入僵局。

根据这个逻辑,如果数据可用,它必须返回而不会阻塞。即使它只是一个可用的字节。

  

假设服务器每50毫秒发送一条消息(100字节),在一个NetworkStream.Read()调用的客户端读取的字节是多少?

每个调用将在一个字节和可用字节数之间返回而不会阻塞。什么都没有,没有别的保证。实际上,您将同时获得一个或多个网络数据包。堆栈保留可用字节没有意义。