为什么使用Boost.ASIO实现的简单HTTP服务器需要睡眠才能正常工作

时间:2014-04-22 09:27:06

标签: c++ networking boost boost-asio

我正在尝试使用Boost.Asio编写一个非常简单的HTTP服务器。这是代码(几乎与Boost.Asio教程中的示例相同)

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <thread>
#include <chrono>

using boost::asio::ip::tcp;

int main()
{
    try
    {
        boost::asio::io_service io_service;

        tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 12345));

        for (;;)
        {
            tcp::socket socket(io_service);
            acceptor.accept(socket);

            const char message[] = "HTTP/1.0 200 OK\r\n\r\n<html><body><i>Hello, world</i></body></html>";

            boost::system::error_code ignored_error;
            boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
        }
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

当我运行此示例时,我尝试使用地址为127.0.0.1:12345的Chrome,但它显示“此网页不可用”。但是,如果我在调试器中逐步启动,它会正确显示斜体“Hello,world”。实际上,如果我在写操作后添加一行std::this_thread::sleep_for(std::chrono::seconds(1));,它将正常工作。我究竟做错了什么?有没有办法避免这种丑陋的黑客攻击?

我在Windows 7上使用Visual Studio 2013.编译为64位代码。

3 个答案:

答案 0 :(得分:3)

<强>更新

客户可能需要Content-Length的想法可能有一些优点。

相反,您可以添加Connection: close标题,这会阻止浏览器将其保持打开状态(因此,EOF&#39;将计为响应的结尾)。


代码看起来很好,它在我的盒子上没有睡眠(Ubuntu / Opera)。

唯一能让我感到震惊的是......有趣的是

  • 您发送终止NUL字符作为回复的一部分:

    $ netcat localhost 12345 | xxd
    0000000: 4854 5450 2f31 2e30 2032 3030 204f 4b0d  HTTP/1.0 200 OK.
    0000010: 0a0d 0a3c 6874 6d6c 3e3c 626f 6479 3e3c  ...<html><body><
    0000020: 693e 4865 6c6c 6f2c 2077 6f72 6c64 3c2f  i>Hello, world</
    0000030: 693e 3c2f 626f 6479 3e3c 2f68 746d 6c3e  i></body></html>
    0000040: 00                                       .
    
  • 您没有收到请求;取决于客户端,这可能会使客户端稍微混淆(?)。我不认为这可能是问题所在,因为有一些宝贵的请求信息被分成包裹

更新实际上,如果您的浏览器执行其他请求(例如GET /favicon.ico,例如并行),则可能会出现问题。您的服务器会同步处理连接,并且可能会同时到达。确保监听套接字允许在&#34;积压&#34;

中至少有1个(或者可能是10个)连接

old answer ('08) says backlog used to be 5 in Asio, by default

答案 1 :(得分:2)

我认为问题是HTTP问题而不是网络问题。

该邮件缺少Content-Length标头,因此您的HTTP/1.1客户端(Chrome)可能正在等待您的服务器关闭连接以标记邮件正文的结尾,请参阅:{{3}第4.4节。尝试将消息更改为:

  "HTTP/1.0 200 OK\r\nContent-Length: 45\r\n\r\n<html><body><i>Hello, world</i></body></html>";

我希望我的邮件正文Content-Length正确。 ;)

答案 2 :(得分:0)

我认为这里的问题是你没有等待请​​求。如果在发送请求之前套接字已关闭,则客户端会将此视为重置连接。你的一秒延迟技巧有效,因为它保持连接打开的时间足够长,以便客户端通过其请求发送。

如果我在写入之前添加一个虚拟请求侦听器,那么您的示例在没有延迟技巧的情况下工作:

std::array<char, 8192> ignored_buffer;
socket.async_read_some(boost::asio::buffer(ignored_buffer),
    [](boost::system::error_code ec, std::size_t bytes_transferred) {});