为什么我用Boost.ASIO实现的简单HTTP服务器需要睡眠才能正常工作
Why do my simple HTTP server implemented with Boost.ASIO needs sleep to work correctly
我正在尝试使用Boost.Asio编写一个非常简单的HTTP服务器。以下是代码(几乎与Boost.Acio教程中的示例相同)
#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 OKrnrn<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位代码。
我认为问题是HTTP
问题,而不是网络问题。
该消息缺少Content-Length
标头,因此您的HTTP/1.1
客户端(Chrome)可能正在等待服务器关闭连接以标记消息正文的结束,请参阅:rfc2616第4.4节。尝试将消息更改为:
"HTTP/1.0 200 OKrnContent-Length: 45rnrn<html><body><i>Hello, world</i></body></html>";
我希望我把你的消息正文的Content-Length
写对了。)
更新
客户可能需要内容长度的想法可能有一些优点。
相反,您可以添加一个Connection: close
标头,这将阻止浏览器保持打开状态(因此"EOF"将被视为响应结束)。
代码看起来很好,在我的盒子(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
,例如并行请求),则可能会出现/a问题。您的服务器同步处理连接,并且这些连接可能同时到达。请确保侦听套接字在"囤积"中允许至少1个(或10个)连接
这个老答案('08)说默认情况下,backlog
在Asio中曾经是5。
我认为这里的问题是您没有等待请求。如果在发送请求之前关闭了套接字,则客户端会将其视为重置连接。您的1秒延迟技巧之所以有效,是因为它可以保持连接打开足够长的时间,以便客户端通过其请求进行发送。
如果我在写入之前添加一个伪请求侦听器,那么您的示例就可以在没有延迟技巧的情况下工作
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) {});
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 为什么STD ::计数将常数传递给Lambda,而不是在弦上工作时而不是字符
- C++程序已停止工作-求解常微分方程