NetworkStream如何在两个方向上工作?

时间:2009-10-23 05:49:46

标签: c# packet tcplistener netstream

我已经阅读了一个Tcp Echo Server的例子,有些事情我不清楚。

TcpClient client = null;
NetworkStream netStream = null;

try {
  client = listener.AcceptTcpClient(); 
  netStream = client.GetStream();

  int totalBytesEchoed = 0;
  while ((bytesRcvd = netStream.Read(rcvBuffer, 0, rcvBuffer.Length)) > 0) {
    netStream.Write(rcvBuffer, 0, bytesRcvd);
    totalBytesEchoed += bytesRcvd;
  }

  netStream.Close();
  client.Close();
} catch {
  netStream.Close();
}

当服务器收到数据包(while循环)时,他将数据读入rcvBuffer并将其写入流中。

令我困惑的是通信中消息的时间顺序。使用netStream.Write()写入的数据是立即发送到客户端(可能仍在发送),还是仅在已经写入流(由客户端)处理的数据之后。

以下问题甚至可以澄清前面的问题:如果客户端通过写入流来发送一些数据,那么数据是否会移动到服务器端的消息队列中等待读取,因此流实际上是“空的”?这可以解释为什么服务器可以立即写入流 - 因为来自流的数据实际上是在其他地方缓冲的......?

3 个答案:

答案 0 :(得分:2)

提示:在该示例中,方法调用NetworkStream.Read正在阻塞。

本书绝对正确 - 对TCP流的原始访问并不意味着任何类型的额外“分块”,例如,在这个例子中,一次可以轻松处理单个字节。但是,批量执行读取和写入(通常使用暴露的缓冲区)可以实现更高效的处理(通常由于较少的系统调用)。网络层和网络硬件也使用自己的缓冲区形式。

实际上无法保证在Reads()成功完成之前实际写入Write()写入的数据:即使数据在一个层中被刷新,也不意味着它在另一个层中被刷新,并且绝对不能保证数据已经回到了客户端。这就是更高级协议发挥作用的地方。

通过这个回声示例,数据可以尽可能快地推送到最后。 Write和Read都将基于底层网络堆栈(特别是发送和接收缓冲区)进行阻塞,每个堆栈都有自己的一系列缓冲区。

[这简化了一些事情 - 人们可以随时查看TCP [协议]本身,它确实对实际数据包流施加了传输特性。]

答案 1 :(得分:2)

TCP连接原则上是全双工。所以你正在处理两个不同的渠道,是的,双方可以同时写作。

答案 2 :(得分:1)

从技术上讲,你执行Read()操作是正确的,你不是在线上读取位。您基本上是在读缓冲数据(由TCP接收并按正确顺序排列的块)。发送时,Flush()理论上应该立即发送数据,但现代TCP堆栈有一些逻辑,如何以适当大小的数据包收集数据并将它们连接到线路。

正如Henk Holterman所解释的,TCP是一种全双工协议(如果所有底层基础设施都支持),因此当您的服务器/客户端读取和写入数据时,更多的是发送和接收数据。它不像服务器发送数据时,客户端会立即读取它。客户端可以发送自己的数据,然后执行Read(),在这种情况下,数据将在网络缓冲区中停留更长时间,并且可以在一段时间之后丢弃,没有人想要读取它。至少我在处理我的supa dupa服务器/客户端库时遇到过这种情况( - 。