3

我们有一个相当复杂的 httphandler 来处理图像。基本上,它以所请求的任何大小流式传输图像的任何部分。一些客户端使用这个处理程序没有任何问题。但是我们有一个位置给我们带来了问题,现在它也给我的开发环境带来了问题。

发生的情况是客户端从未收到任何请求。所以请求 1 和 2 很好,但请求 3 和 4 永远不会结束。

  • 在调试时,我可以看到服务器已准备好并已完成请求。
  • 然而,客户端仍在等待结果(使用 fiddler2 进行调试显示没有收到响应)

我们用来流式传输图像的代码是

        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。

4

4 回答 4

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())。

于 2008-11-11T09:34:28.830 回答
2

垃圾收集不应该是问题。你为什么设置BufferOutput为true呢?鉴于您只想直接写入数据,我认为将其设置为 false 会更合适。

我建议您在诊断中降低一级:使用Wireshark准确查看网络级别发生的情况。Fiddler 非常适合 HTTP 级别,但有时您需要更多细节。

于 2008-11-11T09:34:58.970 回答
2

客户端将限制它向任何一台服务器发出的同时请求的数量。此外,当从需要会话状态(默认)的资源请求时,对需要会话状态的资源的其他请求将被阻止。

使用时,HttpWebResponse您必须处理该对象或其GetResponseStream方法返回的流以完成连接。

您的代码非常混乱。您已经打开了缓冲,设置了内容长度并使用了刷新。这会导致一些奇怪的 HTTP 标头。通常,在您使用缓冲时,会将 Content-Length 标头的设置留给 ASP.NET 来处理。

当您使用刷新时,ASP.NET 假定您随后可能会发送更多数据。在这种情况下,它将使用分块传输。一旦响应完成,就会为最终块发送最后一组标头,每个块作为其自己的长度标头,内容的总长度是从这些标头中得出的。第一个块不应该Content-Length 标头,但是您的代码正在添加该标头。

如果您关闭缓冲并自己将字节泵入输出流,那么您应该自己设置 Content-Length 标头,因为有效地关闭缓冲意味着您对发送给客户端的确切内容负责。Marc 的代码是这种泵的一个简单示例,尽管我会使用更大的缓冲区,或者在 MemoryStream 上,WriteTo 方法会更有效。

于 2008-11-11T15:45:17.957 回答
0

我们还使用 WebRequests 来收集更多信息。那些阻止了连接。将 usings 放在 WebResponses 周围就可以了。

using (HttpWebResponse test_resp = (HttpWebResponse)test_req.GetResponse())
{
}

我不知道那些会阻止其他请求等...

于 2008-11-11T11:52:55.367 回答