【问题标题】:I am unable to send a post request in C++ using socket programming我无法使用套接字编程在 C++ 中发送发布请求
【发布时间】:2021-08-27 05:23:37
【问题描述】:

我正在尝试使用套接字编程在 C++ 中发送一个发布请求,但该请求似乎没有被执行。我不确定 POST 请求的语法是否正确。 这是我发送的请求

string payload = "";
for (int i = 0; i < data.size(); i++)
{
    payload += (data[i].first + "=" + data[i].second);
    if(i<(data.size()-1))
        payload += "&";
}
string request_string = "POST ";
request_string += path;
request_string += " HTTP/1.1\r\n";
request_string += ("Host: " + base_url + "\r\n");
request_string += ("Accept: */*\r\n");
request_string += ("Content-type:application/x-www-form-urlencoded\r\n");
request_string += ("Content-Length: " + to_string(payload.length()));
request_string += "\r\n";

request_string += payload;

这里base_url=httpbin.org和路径=\post和数据是一对("ef","gh") 在控制台上打印时变成了

POST /post HTTP/1.1
Host: httpbin.org
Accept: */*
Content-type: application/x-www-form-urlencoded
Content-Length: 5

ef=gh

整个代码是

string request::post(string url,vector<pair<string,string>> data){

    char buffer[10000];
    int data_len;
    string response;
    int result;

    string base_url = "";
    string path = "";
    bool flag = true;
    for (int i = 0; i < url.length(); i++)
    {
        if (url[i] == '/')
            flag = false;
        if (flag)
            base_url += url[i];
        else
            path += url[i];
    }

    string payload = "";
    for (int i = 0; i < data.size(); i++)
    {
        payload += (data[i].first + "=" + data[i].second);
        if(i<(data.size()-1))
            payload += "&";
    }
    string request_string = "POST ";
    request_string += path;
    request_string += " HTTP/1.1\r\n";
    request_string += ("Host: " + base_url + "\r\n");
    request_string += ("Accept: */*\r\n");
    request_string += ("Content-type:application/x-www-form-urlencoded\r\n");
    request_string += ("Content-Length: " + to_string(payload.length()));
    request_string += "\r\n\r\n";

    request_string += payload;

    cout << request_string << endl;

    struct hostent *host = gethostbyname(base_url.c_str());
    SOCKADDR_IN server;
    server.sin_port = htons(80);
    server.sin_family = host->h_addrtype;
    server.sin_addr.s_addr = *((unsigned long *)host->h_addr);
    memset(&server.sin_zero, 0, 8);

    SOCKET sock;
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    logger("Unable to create a socket", "Successfully created a socket", result);

    result = connect(sock, (SOCKADDR *)(&server), sizeof(server));
    logger("Unable to connect to the server", "Successfully connected to the server", result, sock);

    result = send(sock, request_string.c_str(), strlen(request_string.c_str()), 0);
    logger("Unable to send the request", "Successfully sent the request", result, sock);

    while ((data_len = recv(sock, buffer, 10000, 0)) > 0)
    {
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r')
        {
            response += buffer[i];
            i += 1;
        }
    }
    cout << endl
         << "***********************" << endl;
    cout << "Response" << endl;
    cout << "***********************" << endl;
    return response;

}

网址是httpbin.org/post

请大家指出我犯的错误

【问题讨论】:

  • 您的Content-Length 缺少尾随\r\n。而且您根本不应该在payload 之后附加\r\n\r\n。请求的其余部分看起来很好,所以如果您在进行这些更正后仍然遇到问题,那么您连接服务器和发送request_string 的方式可能有问题,但您没有显示该代码。
  • @RemyLebeau 我做了你提到的更改,但它似乎仍然无法正常工作。我已经更新了我的问题中的代码。

标签: c++ sockets networking


【解决方案1】:

你的代码有很多问题。

  • 您没有检查 gethostbyname() 是否失败(您应该改用 getaddrinfo()),或者验证 host-&gt;h_addrtype 是否仅是 AF_INET

  • 您也没有检查 socket()connect()send() 是否有故障。

  • 您没有考虑到send() 可能无法在一次呼叫中发送整个请求的可能性。您需要循环调用它,直到整个请求都发送完毕。

  • 您的while 循环根本不考虑data_len,因此会超出buffer 的范围,并在最终尝试访问无效内存时可能会崩溃。

  • 坦率地说,您的解析器只是 wholly inadequate 一个可行的 HTTP 客户端。

  • 最重要的是,您希望服务器在响应结束时关闭连接,但您请求的是HTTP/1.1,默认情况下保持连接打开,您并没有请求关闭连接。所以recv() 将在响应完成后最终阻塞(至少一段时间,直到服务器超时),所以你不会看到你的response 字符串被打印到控制台。尝试将"Connection: close\r\n" 添加到您的请求标头中,或者让请求改为请求HTTP/1.0

试试这个:

string request::post(const string &url, const vector<pair<string,string>> &data)
{
    char buffer[10000];
    int data_len;
    string response;
    int result;

    string::size_type pos = url.find('/');
    string base_url = url.substr(0, pos);
    string path = url.substr(pos);

    string payload;
    if (!data.empty())
    {
        payload = (data[0].first + "=" + data[0].second);
        for (size_t i = 1; i < data.size(); ++i)
        {
            payload += ("&" + data[i].first + "=" + data[i].second);
        }
    }

    string request_string = "POST ";
    request_string += path;
    request_string += " HTTP/1.1\r\n"; // or HTTP/1.0
    request_string += ("Host: " + base_url + "\r\n");
    request_string += "Accept: */*\r\n";
    request_string += "Content-Type: application/x-www-form-urlencoded\r\n";
    request_string += ("Content-Length: " + to_string(payload.size()) + "\r\n");
    request_string += "Connection: close\r\n"; // omit this if using HTTP/1.0
    request_string += "\r\n";
    request_string += payload;

    cout << request_string << endl;

    struct hostent *host = gethostbyname(base_url.c_str());
    if (!host)
    {
        logger("Unable to query hostname");
        return "";
    }
    logger("Successfully queried hostname");

    if (host->h_addrtype != AF_INET)
    {
        logger("hostname does not have IPv4 address");
        return "";
    }

    SOCKADDR_IN server = {};
    server.sin_port = htons(80);
    server.sin_family = host->h_addrtype;
    server.sin_addr.s_addr = *((unsigned long *)host->h_addr);

    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0)
    {
        logger("Unable to create a socket");
        return "";
    }
    logger("Successfully created a socket");

    result = connect(sock, (SOCKADDR *)(&server), sizeof(server));
    if (result < 0)
    {
        logger("Unable to connect to the server");
        close(sock);
        return "";
    }
    logger("Successfully connected to the server");

    const char *preq = request_string.c_str();
    data_len = request_string.size();
    do
    {
        result = send(sock, preq, data_len, 0);
        if (result < 0)
        {
            logger("Unable to send the request");
            close(sock);
            return "";
        }
        preq += result;
        data_len -= result;
    }
    while (data_len > 0);
    logger("Successfully sent the request");

    while ((data_len = recv(sock, buffer, sizeof(buffer), 0)) > 0)
    {
        int i = 0;
        do
        {
            if (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r')
            {
                response += buffer[i];
            }
            ++i;
        }
        while (i < data_len);
    }

    if (data_len < 0)
    {
        logger("Unable to read the response");
        close(sock);
        return "";
    }

    cout << endl
         << "***********************" << endl;
    cout << "Response" << endl;
    cout << "***********************" << endl;

    return response;
}

【讨论】:

  • 那行得通。非常感谢您的建议,从现在开始我会记住它们。您能否指导我找到一些好的资源,我可以从这些资源中获取 C++ 中的所有这些 Web 请求,因为似乎严重缺乏此类资源。我想用 C++ @RemyLebeau 制作自己的请求库
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多