使用分块数据时 HttpWebRequest 很慢 [英] HttpWebRequest is slow with chunked data

查看:31
本文介绍了使用分块数据时 HttpWebRequest 很慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 HttpWebRequest 连接到我内部构建的 HTTP 服务器.我的问题是它比通过例如 PostMan (https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en),这可能是利用 Chrome 的内置函数来请求数据.

I'm using HttpWebRequest to connect to my in-house built HTTP server. My problem is that it is a lot slower than connecting to the server via for instance PostMan (https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en), which is probably using the built-in functions in Chrome to request data.

服务器是使用 MSDN 上的这个示例构建的 (http://msdn.microsoft.com/en-us/library/dxkwh6zw.aspx) 并使用大小为 64 的缓冲区.该请求是一个 HTTP 请求,主体中有一些数据.

The server is built using this example on MSDN (http://msdn.microsoft.com/en-us/library/dxkwh6zw.aspx) and uses a buffer size of 64. The request is a HTTP request with some data in the body.

通过 PostMan 连接时,请求被拆分成一堆块,并多次调用 BeginRecieve(),每次接收 64B,耗时约 2 毫秒.除了最后一个,它收到少于 64B.

When connecting via PostMan, the request is split into a bunch of chunks and BeginRecieve() is called multiple times, each time receiving 64B and taking about 2 milliseconds. Except the last one, which receives less than 64B.

但是当使用 HttpWebRequest 与我的客户端连接时,第一个 BeginRecieve() 回调接收 64B 并花费大约 1 毫秒,以下仅接收 47B 并花费近 200 毫秒,最后第三个接收大约 58B 并花费 2 毫秒.

But when connecting with my client using HttpWebRequest, the first BeginRecieve() callback receives 64B and takes about 1 ms, the following receives only 47B and takes almost 200 ms, and finally the third receives about 58B and takes 2ms.

第二个BeginRecieve 怎么样了?我注意到,一旦我开始向 HttpWebRequest 输入流写入数据,连接就会建立,但是直到我调用 GetResponse() 之后数据接收才开始.

What is up with the second BeginRecieve? I note that the connection is established as soon as I start to write data to the HttpWebRequest input stream, but the data reception does not start until I call GetResponse().

这是我的 HttpWebRequest 代码:

Here is my HttpWebRequest code:

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 毫秒的延迟.

What am I doing wrong? Why is it behaving so much differently than a HTTP request from a web browser? This is effectively adding 200ms of lag to my application.

推荐答案

这看起来是 Nagle 算法TCP 延迟确认发生冲突.在您的情况下,您正在发送一个小的 Http 请求(根据您的数字约为 170 字节).这可能小于 MSS(最大段大小),这意味着 Nagle 算法将启动.服务器可能延迟了 ACK,导致延迟高达 500 毫秒.详情请参阅链接.

This looks like a typical case of the Nagle algorithm clashing with TCP Delayed Acknowledgement. In your case you are sending a small Http Request (~170 bytes according to your numbers). This is likely less than the MSS (Maximum Segment Size) meaning that the Nagle Algorithm will kick in. The server is probably delaying the ACK resulting in a delay of up to 500 ms. See links for details.

您可以通过 ServicePointManager.UseNagleAlgorithm = false 禁用 Nagle(在发出第一个请求之前),请参阅 MSDN.

You can disable Nagle via ServicePointManager.UseNagleAlgorithm = false (before issuing the first request), see MSDN.

另请参阅Nagle 的算法对小请求不友好 进行详细讨论,包括 Wireshark 分析.

Also see Nagle’s Algorithm is Not Friendly towards Small Requests for a detailed discussion including a Wireshark analysis.

注意:在您的回答中,您在进行写-写-读时遇到了相同的情况.当您切换到读写时,您就克服了这个问题.但是,我不相信您可以指示 HttpWebRequest(或 HttpClient 就此而言)将小请求作为单个 TCP 写操作发送.在某些情况下,这可能是一个很好的优化.尽管它可能会导致一些额外的数组复制,从而对性能产生负面影响.

Note: In your answer you are running into the same situation when you do write-write-read. When you switch to write-read you overcome this problem. However I do not believe you can instruct the HttpWebRequest (or HttpClient for that matter) to send small requests as a single TCP write operation. That would probably be a good optimization in some cases. Althought it may lead to some additional array copying, affecting performance negatively.

这篇关于使用分块数据时 HttpWebRequest 很慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆