簡體   English   中英

C++ sockets:當客戶端調用connect()時accept()掛起,但是accept()響應HTTP GET請求

[英]C++ sockets: accept() hangs when client calls connect(), but accept() responds to HTTP GET request

我正在嘗試在 C++ 中編寫演示服務器/客戶端程序。 我首先在我的 Macbook 上運行我的服務器程序,打開 ngrok 並將 Internet 上的公共地址轉發到我機器上的本地地址。 當我嘗試運行客戶端程序以連接到服務器時,我看到了一些我不理解的東西:

  1. 如果客戶端嘗試在服務器程序中定義的本地端口連接到 localhost,則服務器按預期接受並且客戶端成功連接,
  2. 如果客戶端嘗試在端口 80(ngrok 的默認值)連接到 ngrok 服務器地址,則客戶端連接,但服務器在接受調用時仍被阻止。 (這個我不明白!)
  3. 如果我向 ngrok 服務器地址發送 HTTP GET 請求,則服務器成功接受連接。

為什么我會看到這些? 在理想情況下,我希望我的服務器接受來自我的客戶端程序的連接,而不僅僅是響應 HTTP GET 請求。

如果有幫助,這是我的代碼:對於客戶,

#include "helpers.hh"
#include <cstdio>
#include <netdb.h>

// usage: -h [host] -p [port]
int main(int argc, char** argv) {
    const char* host = "x.xx.xx.xx"; // use the server's ip here.
    const char* port = "80";

    // parse arguments
    int opt;
    while ((opt = getopt(argc, argv, "h:p:")) >= 0) {
        if (opt == 'h') {
            host = optarg;
        } else if (opt == 'p') {
            port = optarg;
        }
    }

    // look up host and port
    struct addrinfo hints, *ais;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;        // use IPv4 or IPv6
    hints.ai_socktype = SOCK_STREAM;    // use TCP
    hints.ai_flags = AI_NUMERICSERV;
    if (strcmp(host, "ngrok") == 0) {
        host = "xxxx-xxxx-xxxx-1011-2006-00-27b9.ngrok.io";
    }
    int r = getaddrinfo(host, port, &hints, &ais);
    if (r != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r));
        exit(1);
    }

    // connect to server
    int fd = -1;
    for (auto ai = ais; ai && fd < 0; ai = ai->ai_next) {
        fd = socket(ai->ai_family, ai->ai_socktype, 0);
        if (fd < 0) {
            perror("socket");
            exit(1);
        }

        r = connect(fd, ai->ai_addr, ai->ai_addrlen);
        if (r < 0) {
            close(fd);
            fd = -1;
        }
    }
    if (fd < 0) {
        perror("connect");
        exit(1);
    }
    freeaddrinfo(ais);

    // 
    printf("Connection established at fd %d\n", fd);
    FILE* f = fdopen(fd, "a+");
    fwrite("!", 1, 1, f);
    fclose(f);
    while (true) {
    }
    
}

對於服務器:

#include "helpers.hh"

void handle_connection(int cfd, std::string remote) {
    (void) remote;
    printf("Received incoming connection at cfd: %d\n", cfd);
    usleep(1000000);
    printf("Exiting\n");
}


int main(int argc, char** argv) {
    int port = 6162;
    if (argc >= 2) {
        port = strtol(argv[1], nullptr, 0);
        assert(port > 0 && port <= 65535);
    }

    // Prepare listening socket
    int fd = open_listen_socket(port);
    assert(fd >= 0);
    fprintf(stderr, "Listening on port %d...\n", port);

    while (true) {
        struct sockaddr addr;
        socklen_t addrlen = sizeof(addr);

        // Accept connection on listening socket
        int cfd = accept(fd, &addr, &addrlen);
        if (cfd < 0) {
            perror("accept");
            exit(1);
        }

        // Handle connection
        handle_connection(cfd, unparse_sockaddr(&addr, addrlen));
    }
}

與在本地路由器中完成的典型端口轉發相反,ngrok 不是傳輸級別 (TCP) 的端口轉發器,而是 HTTP 級別的請求轉發器。

因此,如果客戶端執行 TCP 連接到外部 ngrok 服務器,則不會轉發任何內容。 只有在客戶端發送了 HTTP 請求后,目的地才會被確定,然后這個請求將被發送到內部機器上的 ngrok 連接器,然后它會啟動到內部服務器的連接並轉發請求。

暫無
暫無

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

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