2013-05-04 38 views
5

我正在編寫一個小型C客戶端/服務器應用程序,但使用外部IP地址時無法使連接正常工作。爲客戶端和服務器的代碼是從here拍攝,尤其是客戶端做:如何使用getaddrinfo連接到使用外部IP的服務器?

char *default_server_name = "localhost"; 
    char *server_name = NULL; 
    int nport = DEFAULT_DAMA_PORT; 
    char port[15]; 

    // Parse the command line options 
    if (parse_options(argc, argv, &server_name, &nport) < 0) { 
     return -1; 
    } 

    if (server_name == NULL) { 
     server_name = default_server_name; 
    } 

    snprintf(port, 15, "%d", nport); 

    // Connect to the server 
    int client_socket; 
    struct addrinfo hints, *servinfo, *p; 
    int rv; 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    if ((rv = getaddrinfo(server_name, port, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     exit(1); 
    } 

    for (p=servinfo; p != NULL; p = p->ai_next) { 
     if ((client_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { 
#ifdef DEBUG 
      perror("socket"); 
#endif 
      continue; 
     } 

     if (connect(client_socket, p->ai_addr, p->ai_addrlen) == -1) { 
      close(client_socket); 
#ifdef DEBUG 
      perror("connect"); 
#endif 
      continue; 
     } 

     // Connected succesfully! 
     break; 
    } 

    if (p == NULL) { 
     // The loop wasn't able to connect to the server 
     fprintf(stderr, "Couldn't connect to the server\n."); 
     exit(1); 
    } 

當服務器:

int nport; 
    char port[15]; 
    if (parse_options(argc, argv, &nport) < 0) { 
     return -1; 
    } 

    snprintf(port, 15, "%d", nport); 

    int server_socket; 
    struct addrinfo hints, *servinfo, *p; 
    int rv; 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 

    if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     exit(1); 
    } 

    for (p=servinfo; p != NULL; p = p->ai_next) { 
     if ((server_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { 
#ifdef DEBUG 
      perror("socket"); 
#endif 
      continue; 
     } 

     if (bind(server_socket, p->ai_addr, p->ai_addrlen) == -1) { 
      close(server_socket); 
#ifdef DEBUG 
      perror("bind"); 
#endif 
      continue; 
     } 

     // We binded successfully! 
     break; 
    } 

    if (p == NULL) { 
     fprintf(stderr, "failed to bind socket\n"); 
     exit(2); 
    } 

    int pl_one, pl_two; 
    socklen_t pl_one_len, pl_two_len; 
    struct sockaddr_in pl_one_addr, pl_two_addr; 

    if (listen(server_socket, 2) < 0) { 
     fatal_error("Error in syscall listen.", 2); 
    } 

    // Get the two clients connections. 
    pl_one_len = sizeof(pl_one_addr); 
    pl_one = accept(server_socket, 
        (struct sockaddr *)&pl_one_addr, 
        &pl_one_len); 
    if (pl_one < 0) { 
     fatal_error("Error in syscall accept.", 3); 
    } 

    pl_two_len = sizeof(pl_two_addr); 
    pl_two = accept(server_socket, 
        (struct sockaddr *)&pl_two_addr, 
        &pl_two_len); 
    if (pl_two < 0) { 
     fatal_error("Error in syscall accept.", 3); 
    } 

如果我在命令行中指定我的機器的IP,並因此客戶端中的server_name被設置爲像151.51.xxx.xxx這樣的字符串,則套接字無法連接到服務器。還使用127.0.0.1顯示了相同的行爲,這讓我覺得,當文檔指出:雲在節點名 參數

您感興趣的主機名。地址可以是主機名稱,例如 「www.example.com」,也可以是IPv4或IPv6地址(作爲字符串傳遞)。

這只是開玩笑。

我做錯了什麼嗎?防火牆等問題是否可能導致客戶端無法使用IP地址進行連接?

注:我已經搜查了很多關於這個問題,有人說在所有避免使用getaddrinfoINADDR_ANY直接填寫,但getaddrinfo文件指出,經過NULLnodename應該已經與INADDR_ANY填寫地址,所以我不明白爲什麼我應該使用舊方法時,新的自動執行此操作。

+0

要使服務器部分按預期工作(爲了能夠接受連接),必須將調用添加到listen()和accept()。您可能想閱讀第9.15章和第9.1章。 – alk 2013-05-04 10:22:57

+0

@alk我明顯有調用'listen'和'accept'(否則,如果客戶端使用'localhost'作爲'server_name',服務器是如何工作的?)。無論如何,我會將它們添加到問題中。 – Bakuriu 2013-05-04 10:34:10

+2

路由器後面的服務器?所需的端口是否打開或轉發? – typ1232 2013-05-04 10:45:05

回答

1

正如註釋中所寫,您嘗試連接到位於路由器後面的網絡中的服務器。

127.0.0.1localhost是操作系統的重定向,不會通過路由器。這就是爲什麼它適合你。

如果指定外部IP地址,則通過路由器進行連接,並且您使用的端口需要在路由器配置中轉發。任何正常的家庭互聯網終端用戶路由器默認阻止任何端口的傳入連接。

相關問題