我与服务器端的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;
}
如果流没有contentLength变量指定的数据量,则可能发生这种情况。 情况并非如此,因为在使用WireShark跟踪tcp流时,我看到整个邮件正文(由contentLength指定)已到达服务器计算机。
仅在第一次使用while循环时才发生这种情况,即仅在第一次流中没有“contentLength”一次尝试读取的字节数时循环必须重新进入。
为什么会卡住并且不继续读取数据?
答案 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并直接从套接字执行读取时,它已解决了问题。