2011-09-24 78 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();