【发布时间】:2016-08-17 16:08:25
【问题描述】:
我很高兴看到有一个跨平台的 TCP/IP 套接字标准出现在 C++ 的 boost 中。到目前为止,我已经能够为我遇到的所有主题找到帮助。但现在我陷入了一种奇怪的行为。我正在 2013 年末的 iMac 上使用 Xcode 7.3.1 进行开发。
我正在为特殊目的开发一个简单的 Web 服务器。下面的代码是演示不良行为的精简版本:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
int main(int argc, const char * argv[]) {
static asio::io_service ioService;
static tcp::acceptor tcpAcceptor(ioService, tcp::endpoint(tcp::v4(), 2080));
while (true) {
// creates a socket
tcp::socket* socket = new tcp::socket(ioService);
// wait and listen
tcpAcceptor.accept(*socket);
asio::streambuf inBuffer;
istream headerLineStream(&inBuffer);
char buffer[1];
asio::read(*socket, asio::buffer(buffer, 1)); // <--- Yuck!
asio::write(*socket, asio::buffer((string) "HTTP/1.1 200 OK\r\n\r\nYup!"));
socket->shutdown(asio::ip::tcp::socket::shutdown_both);
socket->close();
delete socket;
}
return 0;
}
当我访问此服务时,在特定条件下,浏览器会阻塞 20 秒以上。如果我暂停在调试模式下运行的程序,我可以看到 asio::read() 调用正在阻塞。它实际上是在等待浏览器中出现一个字符。这是为什么呢?
让我澄清一下,因为我必须做些什么才能在我的机器上重现这个很奇怪。一旦我启动程序(用于调试),我会从 Chrome 中打开“页面”(http://localhost:2080/)。我可以多次点击刷新,它工作得很好。但是后来我使用了 Firefox(或 Safari),它可能会挂起 20 秒,然后页面按预期显示。现在得到这个。如果在 Firefox 延迟期间,我在 Chrome 中点击 Refresh,Firefox 页面也会立即显示。在另一个实验中,我在 Chrome 中点击 Refresh(工作正常),然后在 Firefox 和 Safari 中点击 Refresh。两人都挂了。我在 Chrome 中点击了 Refresh,所有 3 个都立即显示出来。
在这个实验的一个改变中,当我启动这个程序时,我在 Firefox 或 Safari 中点击了刷新,它们工作得很好。不管我刷新多少次。并且在他们之间来回穿梭。我实际上是按住 CMD-R 来快速刷新这些浏览器。但只要我在同一页面上刷新 Chrome,然后尝试刷新其他两个浏览器,它们就会再次挂起。
自 1993 年左右开始从事 Web 编程,我非常了解 HTTP 标准。最基本的工作流程是浏览器发起 TCP 连接。一旦 Web 服务器接受连接,客户端就会发送一个 HTTP 标头。根页面(“/”)的“GET /\r\n\r\n”之类的东西。服务器通常会读取所有标题行并停止,直到它到达第一个空白行,这表示标题结束和上传内容(例如,POST 表单内容)的开始,Web 应用程序可以随意使用或忽略这些内容.服务器在准备好时使用自己的 HTTP 标头进行响应,通常以“HTTP/1.1 200 OK\r\n”开头,然后是实际页面内容(或二进制文件内容等)。
在我的应用程序中,我实际上使用 asio::read_until(*socket, inBuffer, "\r\n\r\n") 来读取整个 HTTP 标头。由于那是挂起的,我想也许那些其他浏览器正在发送损坏的标头或其他东西。因此,我将样本缩减为仅读取单个字符(应该是“GET /”中的“G”)。一个字符。没有。
作为旁注,我知道我正在同步执行此操作,但我真的想要一个简单的线性演示来展示这种不良行为。我假设这不是导致此问题的原因,但我知道这是可能的。
这里有什么想法吗?在我的用例中,这是很痛苦的,因为服务器最终会响应,但我真的更愿意理解消除这种不良行为。
【问题讨论】:
-
无法在我的 Mac 上重现它
-
进一步研究,我发现 Chrome 发出了两个连接请求,而其他浏览器只发出一个。第一个带有 HTTP 标头,但第二个没有。看来这是 Chrome 中的一个错误。以下帖子相关:stackoverflow.com/questions/4761913/…
-
我确实注意到来自 Chrome 的两个请求,一个针对“/”,另一个针对“favicon.ico”,两个请求似乎都很好。也许您使用的是旧版本的 chrome ?
-
是的,Chrome 会单独尝试获取 /favicon.ico,但这与此无关。
标签: c++ http boost-asio