read(缓冲区,偏移量,长度)如何实际工作,如果我将长度读取为32,这是否意味着它会一直阻塞直到它收到32个字节?
我理解它会在套接字异常或连接关闭的情况下返回异常或0。
如果发送方只发送31个字节,会读取继续阻塞怎么办? 如果这是真的,是否意味着read总是返回等于传递给它的长度的整数?如果剩余的1个字节在一定时间后没有出现,那么cnan如何控制超时。重要且尚未回答
相比之下,如果发送方发送32字节,那么确保读取将被阻塞,直到收到所有32个字节,或者它可以在不读取所有32个字节的情况下出现。
答案 0 :(得分:6)
不,它不会阻止。 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”
答案 1 :(得分:2)
它会阻塞,直到收到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's abstract Read() method实现(必须覆盖)。 Stream.Read()的文档说明了这一点:
实现返回的数量 字节读取。返回值为零 只有当前位置在 流的结束。
这就是为什么代码在没有收到数据时阻塞,并且还没有到达流的末尾。它还接着说:
实施将阻止直到 至少一个字节的数据可以 如果没有数据,请阅读 可用。读取时仅返回0 流中没有更多数据 并且不再期待(例如a 关闭套接字或文件结尾)。 <强>一种 实施可以免费返回更少 字节比请求即使结束 尚未到达流。
答案 2 :(得分:1)
关于超时的问题似乎仍然没有答案。
答案是你可以设置stream.ReadTimeout和stream.WriteTimeout,其中stream是你的NetworkStream对象。这样可以处理完全没有响应的阻塞情况。如果不设置这些值,流将无限期地等待。