设置NetworkStream.ReceiveTimeout不会触发异常

时间:2011-09-25 01:12:06

标签: c# sockets tcp stream

这是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()保持返回零,但没有抛出异常。

这是正常的吗?如果是这样,我怎么能期望处理异常的客户端断开连接?

1 个答案:

答案 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,在这种情况下意味着连接已关闭。