这是this问题的延续。我是网络编程的新手,所以我只是写一些小样本来获得理解,但在解释结果方面有点挣扎。
当发送数据的客户端在发送所有预期数据之前完全关闭时,似乎设置NetworkStream.ReceiveTimeout
无法正常工作。
以下是示例代码:
public static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 10001);
listener.Start();
ThreadPool.QueueUserWorkItem(WriterThread);
using (TcpClient client = listener.AcceptTcpClient())
using (NetworkStream stream = client.GetStream())
{
client.ReceiveTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
stream.ReadTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
ReceiveMessage(stream, 1024);
}
listener.Stop();
Console.WriteLine("Done.");
Console.ReadKey(true);
}
private static void WriterThread(object state)
{
using (TcpClient client = new TcpClient())
{
client.Connect(new IPEndPoint(IPAddress.Loopback, 10001));
using (NetworkStream stream = client.GetStream())
{
byte[] bytes = Encoding.ASCII.GetBytes("obviously less than 1024 bytes");
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(10000); // comment out
}
}
}
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
bufferFill += stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
此版本可以在stream.Read()
调用中正确触发异常。但是,如果我注释掉Thread.Sleep(10000)
,则客户端会关闭连接,但是侦听器无法识别它。主线程卡在while(true)
循环内。 stream.Read()
保持返回零,但没有抛出异常。
这是正常的吗?如果是这样,我怎么能期望处理异常的客户端断开连接?
答案 0 :(得分:3)
是的,这听起来很正常。没有接收或读取超时,因为客户端已断开连接。这意味着没有更多数据可用于读取,并且流将立即返回0,就像记录一样。
我会将您的ReceiveMessage方法修改为以下内容:
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
int bytesRead = stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (bytesRead == 0)
throw new Exception("No more data available.");
bufferFill += bytesRead;
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
显然,如果stream.Read()调用在收到所有预期字节之前返回0,则必须有某种形式的断开连接或类似。无论哪种方式,我们都不会从流中获得更多数据。
编辑:Stream类没有“消息”的概念。如果缓冲区中没有数据,则Read方法将阻塞,直到有更多数据可用。但是,当无法接收更多数据时,它将返回0,在这种情况下意味着连接已关闭。