2011-09-24 96 views
3

我試圖從網絡流中讀取已知長度的消息。 我有點期待NetworkStream.Read()將等待返回,直到我給它的緩衝區數組已滿。如果不是,那麼ReadTimeout屬性有什麼意義?我使用的測試我的理論從NetworkStream讀取特定的字節數

public static void Main(string[] args) 
{ 
    TcpListener listener = new TcpListener(IPAddress.Any, 10001); 
    listener.Start(); 

    Console.WriteLine("Waiting for connection..."); 

    ThreadPool.QueueUserWorkItem(WriterThread); 

    using (TcpClient client = listener.AcceptTcpClient()) 
    using (NetworkStream stream = client.GetStream()) 
    { 
     Console.WriteLine("Connected. Waiting for data..."); 

     client.ReceiveTimeout = (int)new TimeSpan(0, 1, 0).TotalMilliseconds; 
     stream.ReadTimeout = (int)new TimeSpan(0, 1, 0).TotalMilliseconds; 

     byte[] buffer = new byte[1024]; 
     int bytesRead = stream.Read(buffer, 0, buffer.Length); 

     Console.WriteLine("Got {0} bytes.", bytesRead); 
    } 

    listener.Stop(); 

    Console.WriteLine("Press any key to exit..."); 
    Console.ReadKey(true); 
} 

private static void WriterThread(object state) 
{ 
    using (TcpClient client = new TcpClient()) 
    { 
     client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10001)); 
     using (NetworkStream stream = client.GetStream()) 
     { 
      byte[] bytes = Encoding.UTF8.GetBytes("obviously less than 1024 bytes"); 
      Console.WriteLine("Sending {0} bytes...", bytes.Length); 
      stream.Write(bytes, 0, bytes.Length); 
      Thread.Sleep(new TimeSpan(0, 2, 0)); 
     } 
    } 
} 

結果的那

示例代碼:

Waiting for connection... 
Sending 30 bytes... 
Connected. Waiting for data... 
Got 30 bytes. 
Press any key to exit... 

有沒有做一個同步讀取時指定的字節數,只有返回的標準方法被讀過?我確信自己寫一個不是太複雜,但是在TcpClientNetworkStream之間存在超時屬性表明它應該已經以這種方式工作。

+2

超過1k代表,仍然設法省略一個最有用的標籤。 'head-> desk' –

+0

我不明白這是怎麼一個C#相關的問題。不明白assattery。 –

+0

你在用什麼編程語言?它確實像C#一樣。 –

回答

2

TCP是一種不保留應用程序消息邊界的字節流協議。它不能以這種方式將字節「粘合」在一起。讀取超時的目的是指定您想要讀取阻塞的時間。但只要至少可以返回一個字節的數據,讀操作就不會被阻塞。

如果您需要在循環中調用讀取,直到您閱讀完整消息,請執行此操作。 TCP層不關心你認爲是一個完整的信息,這不是它的工作。

+0

好吧,這是有道理的。那麼,不是真的,但它解釋了我的期望錯誤的地方。 –

+0

嗯奇怪的設置ReadTimeout完全沒有,如果編寫器線程退出(通過刪除'Thread.Sleep()')在發送完整的消息之前完全沒有。 –

+1

我不太確定我是否按照你的評論。儘管你設置了ReadTimeout,你是否永遠說讀取塊? –

4

所有可以保證是(之一):

  • 0字節(流的末尾)
  • 至少1個字節(一些數據可用;並不意味着不存在更多的到來或已經可用的)
  • 錯誤(超時等)

要讀取的字節中指定數量的循環...:

int read = 0, offset = 0, toRead = ... 
while(toRead > 0 && (read = stream.Read(buffer, offset, toRead)) > 0) { 
    toRead -= read; 
    offset += read; 
} 
if(toRead > 0) throw new EndOfStreamException();