2011-09-25 25 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