【问题标题】:read() never finishes reading from curl requestread() 永远不会完成从 curl 请求中的读取
【发布时间】:2021-12-17 09:40:56
【问题描述】:

我编写了一个 C++ 程序来监听来自客户端应用程序的请求。客户端应用程序(我没有编写)发送请求,我的服务器应用程序接收并处理它。我可以看到我的服务器读取了整个请求,但客户端报告“连接被拒绝”。所以我通过使用 curl 从命令行发送一些请求来测试它,看看它返回了什么。我遇到的问题是,当我使用 curl 发送请求时,我的服务器应用程序从未完成从套接字读取。它在 while 循环中打印行,告诉我读取了多少字节,但在那之后它挂起。

这是从套接字读取请求的简单代码。当我从真实客户端发送请求时,我看到屏幕上打印了“Request =”行,这意味着它完成了整个请求的读取。但是当我从 curl 发送请求时,它会挂在循环中并且永远不会完成从套接字读取。我不认为问题出在这段代码中。

char message_buffer [INPUT_BUFFER_SIZE + 1];
string request { "" };
int client_fd = client_file_descriptor.front ();
int message_len;

while ((message_len = read (client_fd, &message_buffer, INPUT_BUFFER_SIZE)) > 0)
{
    cout << "Read " << message_len << " bytes of request.\n";
    message_buffer [message_len] = '\0';
    request += message_buffer;
}

cout << "Request = " << request << "\n";

这是我在命令行中使用的 curl 命令。我不经常使用 curl,所以我怀疑问题可能出在我所说的方式上。有人有什么想法吗?

curl -X POST -H "content-type:application/json" -H "content-length:50" "http://192.168.1.44:4444/" --data "{\"id\":111111,\"data\":{\"from\":\"USD\",\"to\":\"ETH,BTC\"}}"

【问题讨论】:

  • curl 可能正在等待响应。所以它不会关闭套接字,因此你的 read 只会阻塞。
  • 您不需要-H "content-length:..."--data 会为您处理。您的代码正在无限循环中从套接字读取,直到 read() 失败。这不是处理 HTTP 请求的正确方法,您需要实际解析它们以发现它们何时结束。请参阅 RFC 2616 Section 4.4RFC 7230 Section 3.3.3。我已经发布了many examples of this,但仅来自客户端,但服务器端逻辑将非常相似

标签: c++ sockets curl


【解决方案1】:

不要(错误)手动计算内容长度。 Curl 会为您做到这一点。

它在 while 循环中打印行,告诉我读取了多少字节,但在那之后它挂起。

具体来说,它会类似于

Read 179 bytes of request.

如果您打印了请求,您会发现您已收到完整的请求:

std::cout << std::quoted(request) << "\n";

打印

Read 179 bytes of request.
"POST / HTTP/1.1
Host: localhost:8787
User-Agent: curl/7.58.0
Accept: */*
content-type:application/json
content-length:50

{\"id\":111111,\"data\":{\"from\":\"USD\",\"to\":\"ETH,BTC\"}}"

您需要发送响应或关闭套接字。我建议您使用库(如 libcurl 或 Boost Beast)来解析 HTTP 请求并检测请求何时完成。

使用 Boost Beast 演示

Live On Coliru

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <boost/beast/http.hpp>
#include <boost/json.hpp>
#include <boost/json/src.hpp>
#include <iostream>
#include <iomanip>

using boost::asio::ip::tcp;
namespace http = boost::beast::http;
namespace json = boost::json;
static constexpr size_t INPUT_BUFFER_SIZE = 1024;

json::value read_request(tcp::socket& s)
{
    http::request<http::string_body>  request;

    boost::beast::flat_buffer buf(INPUT_BUFFER_SIZE);
    http::read(s, buf, request);

    return json::parse(request.body());
}

int main()
{
    boost::asio::io_context ioc;
    tcp::acceptor acc(ioc, {{}, 8787}); 
    acc.listen();
    tcp::socket s = acc.accept();

    auto request = read_request(s);

    // leave server message
    request.as_object().emplace("Server", "Request Received OK");

    http::write(s,
                http::response<http::string_body>( //
                    http::status::ok, 11, serialize(request)));
}

测试

curl -X POST -H "content-type:application/json" "http://127.0.0.1:8787/" --data "{\"id\":111111,\"data\":{\"from\":\"USD\",\"to\":\"ETH,BTC\"}}"

打印

{"id":111111,"data":{"from":"USD","to":"ETH,BTC"},"Server":"Request Received OK"}

【讨论】:

猜你喜欢
  • 2015-07-29
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 2019-03-14
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
相关资源
最近更新 更多