web-dev-qa-db-ja.com

httpWebRequest(基礎となる接続が閉じられました:接続が予期せず閉じられました。)

Webサーバーからのデータを記録するC#アプリケーションを開発しています。次の投稿要求をWebサーバーに送信し、応答を待ちます。

    /// <summary>
    /// Function for obtaining testCgi data 
    /// </summary>
    /// <param name="Parameters"></param>
    /// <returns></returns>
    private string HttpmyPost(string Parameters)
    {
        string str = "No response";
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTestCGI);
        request.Method = "POST";

        byte[] bytes = Encoding.UTF8.GetBytes(Parameters);
        request.ContentLength = bytes.Length;

        Stream requestStream = request.GetRequestStream();
        requestStream.Write(bytes, 0, bytes.Length);
        requestStream.Close();

            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream);

            try
            {
                var result = reader.ReadToEnd();
            stream.Dispose();
            str = result.ToString();
            reader.Dispose();
        }
        catch (WebException ex)
        {
            //System.Windows.Forms.MessageBox.Show(ex.Message);
            System.Diagnostics.Trace.WriteLine(ex.Message);

        }
        finally
        {
            request.Abort();
        }
        return str;
    }

エラーが発生しています

> "The underlying connection was closed: The connection was closed
> unexpectedly"

エラーのデバッグを試みましたが、Firefoxからの投稿要求を確認するためにフィドラーを使用しました。フィドラーが私のプログラムが完璧に機能していたときはいつでも驚いたことに。フィドラーを閉じると、同じエラーが発生します。

Fiddlerはプロキシとして機能しているため、設定の一部が変更される可能性があります。 webclientを使用してみましたが、結果は同じでした。

Pythonでリクエストをコーディングしようとすると、問題なくすべてが正常に機能しました。当然、IronPythonをインストールしてその特定の機能をラップするオプションがありますが、このやり過ぎとエレガントさの欠如を考慮して、よりリーンなアプローチを追求しています。これは設定の調整にすぎないと思われます。

私は修正を試みましたが、私の場合は無関心です。

request.Accept 
request.ReadWriteTimeout 
request.Timeout 
request.UserAgent 
request.Headers
request.AutomaticDecompression 
request.Referer
request.AllowAutoRedirect
//request.TransferEncoding 
request.Expect
request.ServicePoint.Expect100Continue 
request.PreAuthenticate 
request.KeepAlive 
request.ProtocolVersion 
request.ContentType

上記の調整の有無にかかわらず、Fiddlerがデータをキャプチャしているときにコードが機能します。

また、プログラムでエラーが発生することは注目に値するかもしれません

WebResponse response = request.GetResponse();

更新:@EricLawの提案に従って、レイテンシを調べました。私はこの記事を見つけました 間隔を追加するとHttpWebRequestが遅くなります これはNagleアルゴリズムの有効化を示唆しています。現在、閉じられた接続はありませんが、全体的な応答にはわずかな遅れがあります(非同期ではなくwinformsを使用する場合)。

13
NMech

Fiddlerがどのように「魔法のように」物事を修正できるかについて少し書きます: http://blogs.telerik.com/fiddler/posts/13-02-28/help!-running-fiddler-fixes-my- app-

発生している問題は、実際には.NET Framework自体のバグです。 HTTPのルールでは、最初の応答を送信した後、サーバーはいつでもKeepAlive接続を閉じることができます(たとえば、クライアントがKeepAlive動作を要求した場合でも、接続で別の要求を受け入れる必要はありません)。

.NETには、応答が完了した後に接続を閉じる場合にサーバーがConnection: close応答ヘッダーを含めることを期待するバグがあります。サーバーがConnection: Closeヘッダーなしで接続を閉じた場合(RFC2616で完全に有効)、. NETは接続で次の要求を送信しようとしたときに閉じられた接続を検出し、この例外をスローします。 .NETshouldが行うべきことは、静かに新しい接続を作成し、その新しい接続でリクエストを再送することです。

Fiddlerは、サーバーが接続を閉じてもかまわないため、この問題を解決し、クライアントへの接続を維持します。クライアントが2番目の要求を送信すると、Fiddlerはサーバーへの接続の再利用を試み、クライアントが閉じられたことに気づき、静かに新しい接続を作成します。

次の方法で、コード内のこの問題を軽減できます。

  1. 要求でキープアライブを無効にする(これによりパフォーマンスが低下します)
  2. 例外をキャッチして自動的に再試行する
  3. 接続を長く維持するためにサーバーを変更する

アプローチ#3は、サーバーを制御する場合にのみ機能します。また、クライアントは使用後に接続を閉じるゲートウェイ/プロキシの背後にある可能性があるため、おそらくアプローチ#2も使用する必要があります。

28
EricLaw

提案と質問:1)Wiresharkのインストールを実際に見たい場合。送受信されている内容を正確に表示します。そして、それはフィドラーと比較することを可能にします。 request.ContentType = "...."のようなヘッダーが欠落していると思いますが、wiresharkのみがどのヘッダーを表示するか(HttpWebRequestでは送信されず、代わりの代替手段を介して送信されます)を示します。

2)HTTP応答コンテンツ内でエラーが発生していますか?それは例外ですか?それが例外である場合は、catchでキャッチされますか、リクエスト中にtryステートメントの前に発生しますか?

0
Guy