System.IO.Stream.Read卡住了

时间:2011-09-15 08:02:46

标签: c# .net sockets tcp stream

我与服务器端的HTTP连接使用System.IO.Stream.Read来读取HTTP请求正文消息。 问题是,一旦在几分钟内服务器卡在Read语句上,并且在达到套接字超时或客户端已关闭连接之前不会继续。

int bytesRead = 0;

while (bytesRead < contentLength)
{
  int got = stream.Stream.Read(buffer.Buffer, bytesRead, contentLength - bytesRead);
  bytesRead += got;
}
  1. 如果流没有contentLength变量指定的数据量,则可能发生这种情况。 情况并非如此,因为在使用WireShark跟踪tcp流时,我看到整个邮件正文(由contentLength指定)已到达服务器计算机。

  2. 仅在第一次使用while循环时才发生这种情况,即仅在第一次流中没有“contentLength”一次尝试读取的字节数时循环必须重新进入。

  3. 为什么会卡住并且不继续读取数据?

4 个答案:

答案 0 :(得分:1)

我想知道该流是否报告提前终止;你还应该看看Read是否返回了一个非正数,即

while (bytesRead < contentLength)
{
  int got = stream.Stream.Read(
       buffer.Buffer, bytesRead, contentLength - bytesRead);
  if(got <= 0) throw new EndOfStreamException(string.Format(
       "Expected {0} bytes; {1} bytes received", contentLength, bytesRead));
  bytesRead += got;
}

基本上,如果流已关闭,Read的每次调用都将返回非正数(可能为0) - 因此您的while循环将变为紧密循环“读0,加0,读0,加0,读0,加0,读0,加0”。

最后一点,您的方法建议您根据传入的内容长度标头分配byte[];只是一个警告:确保你理智 - 检查这个并将其限制为合理的值,否则DOS攻击是微不足道的。此外,如果可能我建议尽可能尝试使用流API,避免一次将所有内容加载到内存中(除非你限制了传入的大小,如此这不是一个问题。)

答案 1 :(得分:0)

尝试此实现,您的计数(contentLength - bytesRead)是错误的。它应该是缓冲区大小。

byte[] buffer = new byte[bufferSize];
int count;
while ((count = stream.Stream.Read(buffer, 0, buffer.Length)) != 0)
{ 
    // do something with the buffer using count as the end marker
    destination.Write(buffer, 0, count);
}

如果你只想要一个来自流的字节数组,这更像你正在尝试的那样:

byte[] buffer = stream.Stream.ToArray()

或者复制到另一个缓冲区:

byte[] data = stream.Stream.ToArray();
Array.CopyTo(data , buffer.Buffer, data.Length)

答案 2 :(得分:0)

我只对那些没有刷新流的客户端有类似的错误。 System.IO.Stream.Read上的MSDN doc说:“如果没有数据可用,实现将阻塞,直到至少可以读取一个字节的数据。”因此,由于某种原因,没有可用的数据。我认为您可以设置一定的ReadTimeout并在合理的短时间后停止等待更多数据。

此处还发布了一个相关问题:C# NetworkStream.Read oddity。也许他的解决方案也可以帮助你。

答案 3 :(得分:0)

这似乎与我使用NetworkStream的读取方法(上面的代码中看到的调用)和由StreamReader创建的事实有关。将NetworkStream对象传递给它的构造函数。

NetworkStream.Read用于读取http请求消息体,而StreamReader.Read用于读取请求的其余部分(startline,headers ...)。 虽然调用是由同一个线程同步发生的,但它可能是我所经历的行为的原因。

当更改代码只能使用Socket并直接从套接字执行读取时,它已解决了问题。

相关问题