C++ Boost.ASIO async_read_until很慢

Har*_*rry 8 c++ boost boost-asio

我有一个不寻常的问题.我有一个C++ Boost.ASIO Web服务器,并处理传入的请求我正在使用此代码:

boost::asio::async_read_until(
    socket_,
    response_,
    "\r\n\r\n",
    boost::bind(
            &connection::handle_read_headers,
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
    )
);
Run Code Online (Sandbox Code Playgroud)

(其中"socket_"是我的boost :: asio :: ip :: tcp :: socket和"response_"是一个boost :: asio :: streambuf)

我试图抓住请求的标题,然后我再做一次async_read_until,其transfer_exactly匹配从请求标头解析的"Content-Length".问题是上面的代码在一个非常现代的服务器上返回100-900ms(从该读取块,直到调用handle_read_headers()).传入的请求如下所示:

POST /load HTTP/1.1
host: www.mysite.com
Accept: */*
Accept-Encoding: gzip,deflate
Content-type: application/x-www-form-urlencoded
From: googlebot(at)googlebot.com
Origin: http://www.mysite.com
Referer: http://www.mysite.com/another-page/
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
X-Forwarded-For: 66.249.75.103
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Content-Length: 287
Connection: keep-alive

and-the-actual-content-is-here.... (287 bytes worth)
Run Code Online (Sandbox Code Playgroud)

标题似乎以\ r \n \n \n \n结尾,并且它在读取EOF之前触发了handle_read_headers()函数(因此它不会读取整个页面) - 它实际上正在使正则表达式跳闸.这些请求来自谷歌,所以我非常有信心它不会落后于他们.

有什么我可以忽略的,为什么它需要这么长时间才能回来?我可能错过了使用aync_read_until的任何其他捕获?

谢谢!

编辑/更新:好的,现在我很困惑.在尝试兆字节的建议时,我从streambuf切换到字符数组(没有运气),然后我重构我的代码以使用async_read_some而不是async_read_until,并且只需手动扫描分隔符.我还将所有操作系统变量(sysctrl.conf)重置为骨骼默认值(以缩小可能性).不幸的是,我仍然看到以下代码中的100-900ms延迟来自使用相同的传入POST请求调用handle_read():

socket_.async_read_some(
    boost::asio::buffer(response_),
    boost::bind(
        &connection::handle_read,
        shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred
    )
);
Run Code Online (Sandbox Code Playgroud)

response_现在在哪里:

boost::array<char, 4096> response_;
Run Code Online (Sandbox Code Playgroud)

无济于事(同样延迟100-900毫秒).这是不正常的 - 任何想法?

EDIT2:根据Rhashimoto的建议,我启用了处理程序跟踪,并在日志中发现了这种奇怪之处:

[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed)
@asio|1373054319.874916|506*508|socket@0x7fae50004f98.async_receive
@asio|1373054319.874963|506*509|socket@0x7fffd40fed68.async_accept
@asio|1373054319.875008|<506|
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512
@asio|1373054320.609233|508*510|socket@0x7fae50004f98.async_receive
@asio|1373054320.609264|<508|
@asio|1373054320.609284|>510|ec=system:0,bytes_transferred=404
[2013-07-05 15:58:40 - Thread 7fae57e3f700]: Received packet headers (638 bytes) - 734ms elapsed
Run Code Online (Sandbox Code Playgroud)

async_accept和async_receive之间有超过700毫秒的时间.在代码中,它来自这个块(几乎直接来自http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/examples/cpp03_examples.html-服务器的"HTTP Server 2" . cpp和connection.cpp):

new_connection_->start();
new_connection_.reset(new connection(
        io_service_pool_.get_io_service()
));
acceptor_.async_accept(
        new_connection_->socket(),
        boost::bind(
                &server::handle_accept,
                this,
                boost::asio::placeholders::error
        )
);
Run Code Online (Sandbox Code Playgroud)

从开始()到:

void connection::start()
{
    boost::asio::async_read_until(
        socket_,
        response_,
        "\r\n\r\n",
        boost::bind(
            &connection::handle_read_headers,
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
        )
    );
}
Run Code Online (Sandbox Code Playgroud)

并且当调用handle_read_headers()时,已经过了700ms.

有没有人有任何想法?我完全迷失了.

非常感谢!

PSI*_*Alt 4

让我们看一下处理程序日志

[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed)
@asio|1373054319.874916|506*508|socket@0x7fae50004f98.async_receive
@asio|1373054319.874963|506*509|socket@0x7fffd40fed68.async_accept
@asio|1373054319.875008|<506|
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512
@asio|1373054320.609233|508*510|socket@0x7fae50004f98.async_receive
@asio|1373054320.609264|<508|
@asio|1373054320.609284|>510|ec=system:0,bytes_transferred=404
[2013-07-05 15:58:40 - Thread 7fae57e3f700]: Received packet headers (638 bytes) - 734ms elapsed
Run Code Online (Sandbox Code Playgroud)

从日志中我们可以看到async_receive调用了两次:第一次在处理程序设置(#506)后 734 毫秒被调用(#508)。现在,async_receive在处理程序设置 (#508) 后 53 微秒调用第二个 (#510)。就是这样,第二个处理程序调用的触发速度非常快,因为数据(这 404 字节)已经在 TCP 堆栈中准备就绪。

结论:这不是处理程序调用延迟,而是传输延迟。可能是 ISP 或平衡器出现问题,或者 Google 真的不想通过请求和设置延迟来打扰您。

UPD:我想你可以检查一下tcpdump

PS 我不喜欢io_service_pool_HTTP 服务器 2 示例中的实现。这也可能会导致一些问题,但我认为这不是当前的情况。