3

画像を処理するためのかなり複雑な httphandler があります。基本的に、要求された任意のサイズで画像の任意の部分をストリーミングします。一部のクライアントは、このハンドラーを問題なく使用します。しかし、問題が発生する場所が 1 か所あり、開発環境でも問題が発生しています。

何が起こるかというと、クライアントが一部のリクエストで何も受信しないということです。したがって、リクエスト 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 に設定する方が適切だと思います。

診断のレベルを 1 つ下げることをお勧めします。Wiresharkを使用して、ネットワーク レベルで何が起こっているかを正確に確認してください。Fiddler は HTTP レベルに最適ですが、さらに詳細が必要な場合もあります。

于 2008-11-11T09:34:58.970 に答える
2

クライアントは、1 つのサーバーに対して行う同時要求の数を制限します。さらに、セッション状態を必要とするリソースから要求する場合 (デフォルト)、セッション状態を必要とするリソースに対する他の要求はブロックされます。

使用するとき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 に答える