我们有一个相当复杂的httphandler用于处理图像。基本上它以任何请求的大小流式传输图像的任何部分。有些客户端使用此处理程序没有任何问题但是我们有一个位置给我们带来了问题,现在它也给我的开发环境带来了问题。
发生的事情是客户端在某些请求中从未收到任何内容。因此请求1和2都没问题,但请求3和4永远不会结束。
我们用于流式传输图像的代码是
if (!context.Response.IsClientConnected)
{
imageStream.Close();
imageStream.Dispose();
return;
}
context.Response.BufferOutput = true;
context.Response.ContentType = "image/" + imageformat;
context.Response.AppendHeader("Content-Length", imageStream.Length.ToString());
if (imageStream != null && imageStream.Length > 0 && context.Response.IsClientConnected)
context.Response.BinaryWrite(imageStream.ToArray());
if (context.Response.IsClientConnected)
context.Response.Flush();
imageStream.Close();
imageStream.Dispose();
imageStream是一个带有图像内容的MemoryStream。
在调用response.Flush()之后,我们进行了一些清理并将摘要写入事件日志。
我们还在每次请求后调用GC.Collect(),因为我们在内存中使用的对象变得非常大。我知道这不是一个好习惯,但它会给我们带来麻烦吗?
在IIS 5(Win XP)和IIS 6(Win 2003)中都没有返回请求的问题,我们使用.NET framework v2。
答案 0 :(得分:4)
首先,有更好的方法来处理使用数组进行整个事情的流(例如,MemoryStream
可能在这里是不必要的。)
我会想到一个循环:
const int BUFFER_SIZE = 4096; // pick your poison
bute[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while((bytesRead = inStream.Read(buffer, 0, BUFFER_SIZE)) > 0)
{
outStream.Write(buffer, 0, bytesRead);
}
您也应该在禁用缓冲(.Response.BufferOutput = false
)的情况下执行此操作。
重新解决问题,我怀疑你没有写好足够数据/关闭回复(.Response.Close()
)。
答案 1 :(得分:2)
垃圾收集应该不是问题。为什么要将BufferOutput
设置为true?鉴于您只想直接写入数据,我认为将其设置为false会更合适。
我建议您在诊断中降低一级:使用Wireshark查看网络级别的确切情况。 Fiddler非常适合HTTP级别,但有时您需要更多细节。
答案 2 :(得分:2)
客户端将限制它将对任何一台服务器发出的同时请求数。此外,当从需要会话状态的资源(默认)请求其他需要会话状态的资源时,将阻止。
使用HttpWebResponse
时,您必须处置该对象或其GetResponseStream
方法返回的流以完成连接。
您的代码非常令人困惑。你已经开启了缓冲,设置了内容长度并使用了刷新。这会导致一些奇怪的HTTP标头。通常使用缓冲,您可以将Content-Length标头的设置保留给ASP.NET来处理。
使用flush时,假设您可以随后发送更多数据。在这种情况下,它将使用分块传输。一旦响应完成,就为最终的块发送最终的头部集合,每个块作为其自己的长度头部,并且内容的总长度从这些部分导出。第一个块应不具有Content-Length标头,但是您的代码正在添加该标头。
如果您关闭缓冲并将字节输入输出流然后,您应该自己设置Content-Length标头,因为有效缓冲关闭意味着您要确切地负责发送到客户。 Marc的代码是这种泵的一个简单例子,虽然我会使用更大的缓冲区,或者在MemoryStream上使用WriteTo方法会更有效。
答案 3 :(得分:0)
我们还使用WebRequests收集更多信息。那些阻止了联系。在WebResponses周围使用是有把戏的。
using (HttpWebResponse test_resp = (HttpWebResponse)test_req.GetResponse())
{
}
我不知道那些可以阻止其他请求......