4

HttpWebRequest を使用して、社内で構築された HTTP サーバーに接続しています。私の問題は、たとえば PostMan ( https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en )を介してサーバーに接続するよりもはるかに遅いことです。 Chrome の組み込み関数を使用してデータを要求します。

サーバーは、MSDN ( http://msdn.microsoft.com/en-us/library/dxkwh6zw.aspx ) でこの例を使用して構築され、64 のバッファー サイズを使用します。要求は、本文にいくつかのデータを含む HTTP 要求です。 .

PostMan 経由で接続する場合、リクエストはチャンクの束に分割され、BeginRecieve() が複数回呼び出され、毎回 64B を受信して​​約 2 ミリ秒かかります。64B未満を受け取る最後のものを除いて。

しかし、HttpWebRequest を使用してクライアントに接続すると、最初の BeginRecieve() コールバックは 64B を受信して​​約 1 ミリ秒かかり、次は 47B のみを受信して​​約 200 ミリ秒かかり、最後に 3 番目は約 58B を受信して​​ 2 ミリ秒かかります。

2 番目の BeginRecieve はどうなっていますか? HttpWebRequest 入力ストリームへのデータの書き込みを開始するとすぐに接続が確立されますが、GetResponse() を呼び出すまでデータの受信は開始されません。

ここに私の HttpWebRequest コードがあります:

var request = (HttpWebRequest)WebRequest.Create(url);

request.Method = verb;
request.Timeout = timeout;
request.Proxy = null;
request.KeepAlive = false;
request.Headers.Add("Content-Encoding", "UTF-8");
System.Net.ServicePointManager.Expect100Continue = false;
request.ServicePoint.Expect100Continue = false;

if ((verb == "POST" || verb == "PUT") && !String.IsNullOrEmpty(data))
{
    var dataBytes = Encoding.UTF8.GetBytes(data);

    try
    {
        var dataStream = request.GetRequestStream();
        dataStream.Write(dataBytes, 0, dataBytes.Length);
        dataStream.Close();
    }
    catch (Exception ex)
    {
        throw;
    }

}

WebResponse response = null;
try
{
    response = request.GetResponse();
}
catch (Exception ex)
{
    throw;
}

var responseReader = new StreamReader(rStream, Encoding.UTF8);
var responseStr = responseReader.ReadToEnd();

responseReader.Close();
response.Close();

私は何を間違っていますか?Web ブラウザーからの HTTP 要求とは異なる動作をするのはなぜですか? これにより、実質的に 200 ミリ秒の遅延がアプリケーションに追加されます。

4

4 に答える 4

4

これは、 Nagle アルゴリズムがTCP Delayed Acknowledgmentと衝突する典型的なケースのようです。あなたの場合、小さなHTTPリクエストを送信しています(数字によると〜170バイト)。これは、MSS (最大セグメント サイズ) よりも小さい可能性が高く、Nagle アルゴリズムが開始されることを意味します。サーバーが ACK を遅延させているため、最大 500 ミリ秒の遅延が発生している可能性があります。詳細については、リンクを参照してください。

ServicePointManager.UseNagleAlgorithm = false(最初のリクエストを発行する前に) Nagle を無効にすることができます。 MSDNを参照してください。

また、Wireshark の分析を含む詳細な議論については、Nagle のアルゴリズムは小さな要求に対して友好的ではないを参照してください。

注:あなたの答えでは、書き込み、書き込み、読み取りを行うときに同じ状況に陥っています。読み書きに切り替えると、この問題を解決できます。ただし、単一の TCP 書き込み操作として小さな要求を送信するように HttpWebRequest (または HttpClient) に指示できるとは思いません。場合によっては、これがおそらく適切な最適化になるでしょう。ただし、追加の配列コピーが発生する可能性があり、パフォーマンスに悪影響を及ぼします。

于 2013-10-28T19:14:27.823 に答える
3

200 ミリ秒は、Nagle アルゴリズムの一般的なレイテンシです。これにより、サーバーまたはクライアントが Nagling を使用している疑いが生じます。サーバーとして MSDN のサンプルを使用しているとのことですが、そうですね。適切なサーバーを使用するか、Nagling を無効にします。

組み込みの HttpWebRequest クラスに不要な 200 ミリ秒のレイテンシがあると仮定することはほとんどありません。他の場所を見てください。コードを見て問題を見つけてください

于 2013-08-27T15:58:16.790 に答える
2

HttpWebRequest は本当に遅いようです。

面白いことに、ソケットを使用して独自の HTTP クライアントを実装したところ、HttpWebRequest が非常に遅い理由の手がかりが見つかりました。ASCII ヘッダーを独自のバイト配列にエンコードしてストリームで送信し、その後にデータからエンコードされたバイト配列を送信した場合、ソケットベースの HTTP クライアントは HttpWebRequest とまったく同じように動作しました。最初に 1 つのバッファーにデータを入力します (ヘッダー)、次に別のバッファーを部分的に (ヘッダーの残りの部分) 使用し、200 ミリ秒待機してから、残りのデータを送信します。

コード:

TcpClient client = new TcpClient(server, port);
NetworkStream stream = client.GetStream();

// Send this out
stream.Write(headerData, 0, headerData.Length);
stream.Write(bodyData, 0, bodyData.Length);
stream.Flush();

解決策はもちろん、ストリームに送信する前に 2 バイト配列を追加することでした。私のアプリケーションは現在、期待どおりに動作しています。

単一ストリームのコードは次のように記述します。

TcpClient client = new TcpClient(server, port);
NetworkStream stream = client.GetStream();

var totalData = new byte[headerBytes.Length + bodyData.Length];
Array.Copy(headerBytes,totalData,headerBytes.Length);
Array.Copy(bodyData,0,totalData,headerBytes.Length,bodyData.Length);

// Send this out
stream.Write(totalData, 0, totalData.Length);
stream.Flush();

また、HttpWebRequest は、要求ストリームに書き込む前にヘッダーを送信するように見えるので、最初のコード サンプルのように実装される可能性があります。これはまったく意味がありますか?

これが同じ問題を抱えている人の役に立てば幸いです!

于 2013-08-27T15:07:18.580 に答える