2011-09-25 26 views
0

这是this问题的延续。我是网络编程的新手,所以我只是写小样本的东西来获得理解,但在解释结果方面有些挣扎。设置NetworkStream.ReceiveTimeout不触发异常

看起来设置NetworkStream.ReceiveTimeout当发送所有预期数据之前应该发送数据的客户端关闭时,它不能正常工作。

下面是示例代码:

stream.Read()呼叫
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); 
    } 
} 

这个版本工作正常触发例外。但是,如果我注释掉Thread.Sleep(10000),客户端将关闭连接,但侦听器无法识别它。主线卡在while(true)循环内。 stream.Read()一直返回零,但不会抛出异常。

这是正常的吗?如果是的话,我如何处理异常的客户端断开连接?

+0

当'Stream.Read()'返回零时,它表明你已经到达流的ned。 – svick

回答

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

+0

如果连接被用来发送多个消息间隔不活动,那么这仍然是真的吗? –

+0

是的。 Stream类没有“消息”的概念。 Read方法阻塞,直到更多数据变为可用,如果缓冲区中没有数据。然而,当没有更多的数据可以被接收时,它将返回0,在这种情况下,这意味着连接被关闭。 – DeCaf

+0

+1,很好的解释。我通常编辑我的答案以添加更新的信息,并发布“阅读我的更新”提交。它可以更容易地为未来的读者找到所有信息。 – jgauffin