C#Networkstream.read()

read(缓冲区,偏移量,长度)如何实际工作,如果我将长度读取为32,这是否意味着它会一直阻塞直到它收到32个字节?

我知道它会返回和exception,或者在套接字exception或连接关闭时分别为0。

如果发送方只发送31个字节,会读取继续阻塞吗? 如果这是真的,是否意味着read总是返回等于传递给它的长度的整数? 以及如果剩余的1个字节在一定时间后没有出现,我如何控制超时。

重要但尚未回答

相反,如果发送方发送32字节,那么确保读取将阻塞直到接收到所有32个字节,或者它可以在不读取所有32个字节的情况下发出。

不,它不会阻止。 Read操作读取尽可能多的数据,最多可达size参数指定的字节数。 来源: http : //msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read.aspx

鉴于它不会等待额外的1个字节,如果你期望它,你应该实现一个循环来继续读取流。 您可以退出循环,但感觉最好。


更新:当我说“根本没有阻塞时,我错了。如果没有可用于读取的数据,Read方法返回0”,但当我说它不会阻止等待填充整个缓冲区时我是正确的它是Kazoom问题中描述的场景。

更新以演示NetworkStream.Read阻塞等待第一个字节,但不阻止等待填充整个缓冲区

创建控制台项目

一方面,你有听众:

IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); TcpListener listener = new TcpListener(ep); listener.Start(); TcpClient client = listener.AcceptTcpClient(); NetworkStream s = client.GetStream(); byte[] buffer = new byte[32]; Console.WriteLine(s.Read(buffer, 0, 32)); Console.WriteLine("Press any key to continue..."); Console.Read(); 

另一方面,我们只发送一个字节:

 IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); TcpClient client = new TcpClient(); client.Connect(ep); client.GetStream().Write(new byte[] { 60 }, 0, 1); Console.WriteLine("Press any key to continue..."); Console.Read(); 

双方将一直运行,直到他们到达Console.Read()。 请注意,侦听器不会阻止Read。

听众将打印“1”

它将阻塞,直到它收到32个字节,或者连接关闭。 应使用异步方法BeginRead()和EndRead()来提供非阻塞读取。

下面是一些示例代码,清楚地展示了阻塞效果。

  Socket one = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Socket two = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); one.Bind(ep); one.Listen(1); two.Connect("127.0.0.1", 12345); one = one.Accept(); NetworkStream s = new NetworkStream(two); byte[] buffer = new byte[32]; s.Read(buffer, 0, 32); 

编辑

尽管这段代码产生了阻塞效果,但这只是因为NetworkStream实现了Stream的抽象Read()方法 (必须重写)。 Stream.Read()上的文档说明了这一点:

实现返回读取的字节数。 仅当位置当前位于流的末尾时,返回值才为零。

这就是为什么代码在没有收到数据时阻塞,并且还没有到达流的末尾。 它还继续说:

在没有数据可用的情况下,实现将阻塞,直到可以读取至少一个字节的数据 。 只有当流中没有更多数据并且不再需要更多数据时(例如关闭的套接字或文件末尾),read才返回0。 即使尚未到达流的末尾,实现也可以自由返回比请求更少的字节。

关于超时的问题似乎仍然没有答案。

答案是你可以设置stream.ReadTimeout和stream.WriteTimeout,其中stream是你的NetworkStream对象。 这样可以处理完全没有响应的阻塞情况。 如果不设置这些值,流将无限期地等待。