2013-05-04 13 views
5

Sto scrivendo una piccola applicazione client/server C, ma non riesco a far funzionare la connessione quando si utilizza l'indirizzo IP esterno. Il codice per client e server è preso da here, in particolare, i clienti fanno:Come utilizzare getaddrinfo per connettersi a un server usando l'IP esterno?

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); 
    } 

Mentre il server:

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); 
    } 

Se specifico l'IP della mia macchina nella riga di comando, e quindi lo server_name nei client è impostato su una stringa come 151.51.xxx.xxx, quindi i socket non possono connettersi al server. Anche utilizzando 127.0.0.1 mostra lo stesso comportamento, che mi fa pensare che quando la documentazione afferma:

Il nome host che ti interessa va nel parametro nomenodo . L'indirizzo può essere un nome host, ad esempio "www.example.com" o un indirizzo IPv4 o IPv6 (passato come stringa).

è solo scherzando.

Sto facendo qualcosa in modo errato? Potrebbe esserci qualche problema con il firewall ecc. Che impedisce ai client di connettersi usando gli indirizzi IP?

Nota: Ho già cercato un sacco per questo problema e alcune persone dicono di evitare l'uso getaddrinfo a tutti e riempire direttamente con INADDR_ANY, ma la documentazione getaddrinfo afferma che passando NULL come nodename dovrebbe già riempire l'indirizzo con INADDR_ANY, quindi non vedo perché dovrei usare il vecchio metodo quando il nuovo lo fa automaticamente.

+0

Affinché la parte server funzioni come previsto (per poter accettare le connessioni) è necessario aggiungere chiamate a 'listen()' e 'accept()'. Ti potrebbe piacere leggere il capitolo 9.15 e il capitolo 9.1. – alk

+0

@alk Ovviamente ho chiamate a 'listen' e' accept' (altrimenti come mai il server funziona se il client usa' localhost' come 'server_name'?). Li aggiungerò comunque alla domanda. – Bakuriu

+2

Il server è dietro un router? Le porte richieste sono aperte o inoltrate? – typ1232

risposta

1

Come scritto nei commenti si sta tentando di connettersi a un server che si trova in una rete dietro un router.

127.0.0.1 o localhost sono reindirizzamenti del sistema operativo e non vanno oltre il router. Ecco perché ha funzionato per te.

Se si specifica un indirizzo IP esterno, la connessione viene effettuata tramite il router e le porte che si utilizzano devono essere inoltrate nella configurazione del router. Per impostazione predefinita, qualsiasi normale router di utente finale di Internet di casa blocca le connessioni in entrata da qualsiasi porta.

Problemi correlati