簡體   English   中英

C 原始套接字 HTTP 請求總是返回狀態 400

[英]C Raw Sockets HTTP Request Always Returning Status 400

我通常會寫一堆 Typescript/Javascript 代碼,我認為 HTTP 協議是理所當然的。 我決定編寫一個 C++ 程序,該程序可以使用套接字向給定的 URL 發出 GET 請求,以了解有關 HTTP 工作原理的更多信息。 我已經編碼了我認為我應該做的基本結構:

  1. 創建套接字
  2. 將套接字連接到主機
  3. 逐字節發送請求
  4. 逐字節接收響應

問題是請求總是返回狀態碼 400:

>>>> Request sent:
GET /links HTTP/1.1


>>>> Response received:
HTTP/1.1 400 Bad Request
Server: cloudflare
Date: Sun, 11 Oct 2020 05:57:11 GMT
Content-Type: text/html
Content-Length: 155
Connection: close
CF-RAY: -

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

這是我用來創建套接字並將其連接到主機的代碼:

    // ---- Create the socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("!!!! ERROR opening socket");

    // ---- Look up (and parse) the server host, route
    std::string host = parseHost(url);
    std::string route = parseRoute(url);
    struct hostent *server = gethostbyname(host.c_str()); // host.c_str())
    if (server == NULL)
        error("!!!! ERROR, no such host");

    // ---- Fill in the server address structure
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT); // PORT
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);

    // ---- Connect the socket to the given url's host
    const int didConnect = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (didConnect < 0) error("!!!! ERROR connecting to host");

如果這個邏輯看起來是正確的,那么這里是發送請求和接收響應的代碼:

    // ---- Send the GET request byte by byte
    int bytes, sent, received;
    char response[MAX_CONTENT_LENGTH];
    int total = sizeof(response) - 1;
    sent = 0;
    std::string message = "GET " + route + "HTTP/1.1" + "\r\n\r\n";
    do
    {
        bytes = write(sockfd, message.c_str() + sent, total - sent);
        if (bytes < 0) error("!!!! ERROR writing message to socket");
        if (bytes == 0) break;
        sent += bytes;
    } while (sent < total);

    std::cout << ">>>> Request sent: \n" << message << std::endl;

    // ---- Receive the response byte by byte
    memset(response, 0, sizeof(response));
    total = sizeof(response) - 1;
    received = 0;
    do {
        bytes = read(sockfd, response + received, total - received);
        if (bytes < 0)
            error("!!!! ERROR reading response from socket");
        if (bytes == 0)
            break;
        received += bytes;
    } while (received < total);

    if (received == total)
        error("!!!! ERROR storing complete response from socket (not enough space allocated)");
  • TLDR:我是否將正確的字符數組發送到服務器? 截至目前,它具有以下格式: "GET /route HTTP/1.1\\r\\n\\r\\n" 我是否忘記了讓服務器知道這是 GET 請求的任何標頭/其他信息?
>>>> Request sent:
GET /links HTTP/1.1

這不是有效的 HTTP 請求。 它缺少帶有目標域名的 Host 標頭,即它至少應該是這樣的

GET /links HTTP/1.1
Host: www.example.com

除此之外,您的代碼只是嘗試讀取數據,直到服務器關閉連接或達到內部緩沖區的大小。 但是 HTTP/1.1 默認使用持久連接。 因此,服務器可能會在響應發送后簡單地保持連接打開,因為它期待您的下一個請求,這意味着您的程序將簡單地阻止什么都不做。

請注意,HTTP 遠比看起來復雜。 如果您想實現它而不是使用現有庫,請研究實際標准 這就是標准的用途。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM