我使用System.IO.Stream.Read与服务器端建立了HTTP连接,以读取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"字节数来读取一次尝试,而必须重新进入while循环。
为什么卡住了,不能继续读取数据?
我想知道流是否报告提前终止;您还应该查看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,添加0,读取0,添加0"的紧密循环。
作为最后一点,您的方法建议您根据传入的内容长度头分配byte[]
;只是一个警告:请确保您对此进行了安全检查,并将其限制为合理的值,否则DOS攻击是微不足道的。此外,如果可能的话我建议尽量使用流API,以避免必须一次将其全部加载到内存中(除非您限制了传入的大小,因此这不是一个问题)。
尝试这个实现,你的计数(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)
我有过类似的错误,只有客户端没有刷新他们的流。System.IO.Stream.Read上的MSDN文档说:"在没有可用数据的情况下,实现将阻塞直到至少一个字节的数据可以被读取。"由于某些原因,没有可用的数据。我认为你可以设置一个特定的ReadTimeout
,并在相当短的时间后停止等待更多的数据。
这似乎与我使用NetworkStream的Read方法(这是在上面的代码中看到的调用)和通过将NetworkStream对象传递给它的构造函数创建的StreamReader的事实有关。
NetworkStream。Read用于读取http请求消息体,而StreamReader。Read用于读取请求的其余部分(起始行,标头…)。虽然调用是由同一个线程同步发生的,但它可能是我所经历的行为的原因。
当将代码更改为仅与套接字一起工作并直接从套接字执行读取时,它已经修复了这个问题。