NetworkStream 如何在两个方向上工作?
我读过 Tcp Echo 服务器的示例,但有些事情我不清楚。
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() 写入的数据是立即发送到客户端(甚至可能仍在发送),还是仅在已写入流(由客户端)处理的数据之后发送。
下面的问题甚至可以澄清前面的问题:如果客户端通过写入流来发送一些数据,那么该数据是否会移动到服务器端的消息队列中等待读取,因此流实际上是“空”?这可以解释为什么服务器可以立即写入流 - 因为来自流的数据实际上在其他地方缓冲......?
I've read an example of a Tcp Echo Server and some things are unclear to me.
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();
}
When the server receives a packet (the while loop), he reads the data into rcvBuffer and writes it to the stream.
What confuses me is the chronological order of messages in communication. Is the data which was written with netStream.Write() sent immediately to the client (who may even still be sending), or only after the data which is already written to the stream (by client) processed.
The following question may even clarify the previous: If a client sends some data by writing to the stream, is that data moved to the message queue on the server side waiting to be read so the stream is actually "empty"? That would explain why the server can immediately write to stream - because the data which comes from the stream is actually buffered elsewhere...?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
TCP 连接原则上是全双工的。所以你正在处理两个独立的通道,是的,双方可以同时写入。
A TCP connection is, in principal, full duplex. So you are dealing with 2 separate channels and yes, both sides could be writing at the same time.
提示:在该示例中,方法调用 NetworkStream.Read 是阻塞的。
这本书是绝对正确的——对 TCP 流的原始访问并不意味着任何额外的“分块”,并且在这个例子中,一次可以轻松处理一个字节。但是,批量执行读取和写入(通常使用公开的缓冲区)可以实现更有效的处理(通常是由于系统调用较少)。网络层和网络硬件也采用它们自己的缓冲区形式。
实际上并不能保证从 Write() 写入的数据实际上会在更多 Reads() 成功完成之前被写入:即使数据在一层中刷新,也不意味着它在另一层中刷新,并且绝对不能保证数据已回到客户手中。这就是更高级别协议发挥作用的地方。
在这个回显示例中,数据只是尽可能快地被推送。写入和读取都将根据底层网络堆栈(特别是发送和接收缓冲区)进行阻塞,每个堆栈都有自己的一系列缓冲区。
[当然,这稍微简化了事情——人们总是可以查看 TCP [协议] 本身,它确实将传输特性强加于实际的数据包流。]
Hint: The method call NetworkStream.Read is blocking in that example.
The book is absolutely correct -- raw access to TCP streams does not imply any sort of extra "chunking" and, in this example for instance, a single byte could easily be processed at a time. However, performing the reading and writing in batches (normally with exposed buffers) can allow for more efficient processing (often as a result of less system calls). The network layer and network hardware also employ there own forms of buffers.
There is actually no guarantee that data written from Write() will actually be written before more Reads() successfully complete: even if data is flushed in one layer it does not imply it is flushed in another and there is absolutely no guarantee that the data has made its way back over to the client. This is where higher-level protocols come into play.
With this echo example the data is simply shoved through as fast as it can be. Both the Write and the Read will block based upon the underlying network stack (the send and receive buffers in particular), each with their own series of buffers.
[This simplifies things a bit of course -- one could always look at the TCP [protocol] itself which does impose transmission characteristics on the actual packet flow.]
从技术上讲,您是对的,当执行 Read() 操作时,您并没有从线路上读取位。您基本上是在读取缓冲数据(由 TCP 接收并按正确顺序排列的数据块)。发送时,您可以使用 Flush() ,理论上应该立即发送数据,但现代 TCP 堆栈有一些逻辑如何以适当大小的数据包收集数据并将其突发到线路。
正如 Henk Holterman 所解释的,TCP 是一个全双工协议(如果所有底层基础设施都支持的话),因此发送和接收数据更多的是当服务器/客户端读取和写入数据时。这不像服务器发送数据时,客户端会立即读取它。客户端可以发送自己的数据,然后执行 Read(),在这种情况下,数据将在网络缓冲区中保留更长时间,并且在一段时间后无人愿意读取它时可以将其丢弃。至少我在处理我的 supa dupa 服务器/客户端库(-.
You are right that technically when performing Read() operation, you are not reading bits off the wire. You are basically reading buffered data (chunks received by a TCP and arranged in a correct order). When sending you can Flush() that should in theory should send data immediately, but modern TCP stacks have a bit of logic how to gather data in appropriate size packets and burst them to the wire.
As Henk Holterman explained, TCP is a full duplex protocol (if supported by all underlying infrastructure), so sending and receiving data is more of when you server/client reads and writes data. It's not like when you server send data, a client will read it immediately. Client can be sending it's own data and then perform Read(), in this case data will stay in network buffer longer and can be discarded after some time it no-one want to read it. At least I've experienced this when dealing with my supa dupa server/client library (-.