2015-05-20 30 views
5

Sto scrivendo un'applicazione C che viene eseguita come systemd service all'avvio (distro: Arch Linux) e che deve connettersi a un server. Poiché l'applicazione viene eseguita all'avvio, alla fine capita che la connessione di rete non sia ancora stata stabilita. Ciò porta naturalmente a un fallimento della prima funzione che ne richiede uno, che nel mio caso è getaddrinfo.Se getaddrinfo fallisce una volta fallisce per sempre (anche dopo che la rete è pronta)

Quindi ho pensato di scrivere un ciclo che chiama ripetutamente lo getaddrinfo finché non supera una volta che la rete è pronta. Purtroppo ho trovato che getaddrinfo continua a non riuscire con name or service not known anche dopo che la connessione è stata stabilita.

Sono in grado di eseguire il ping del server tramite il relativo nome host ma non lo eseguirà ancora getaddrinfo. Se interrompo l'applicazione ed eseguo di nuovo, tutto funziona correttamente. Se la connessione di rete è già stabilita prima della prima chiamata, getaddrinfo funziona correttamente.

Apparentemente, se getaddrinfo non è riuscito una volta perché la rete non era pronta, fallirà per sempre. Sembra non essere a conoscenza della connessione ora esistente. Quando si utilizza il deprecato gethostbyname, il comportamento è lo stesso.

Qual è il motivo di questo comportamento? C'è un modo per forzare getaddrinfo per aggiornare le variabili interne (se esistono) o simili che potrebbero spiegare perché la funzione crede ancora che non vi sia alcuna connessione? Esiste un'altra funzione che dovrei chiamare in precedenza per verificare se la rete è pronta?

Vorrei evitare un ritardo che attende un po 'di tempo, aspettando che la rete sia collegata in seguito. Preferirei anche controllare una connessione dalla mia applicazione e non avere uno script bash prima di controllarlo e quindi avviare l'applicazione.

risposta

4

Si può capire la risposta compilando il seguente programma di test, e seguendo le istruzioni riportate di seguito:

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) 
{ 
    while (1) 
    { 
     struct addrinfo *res; 
     int rc=getaddrinfo(argv[1], "http", NULL, &res); 

     printf("getaddrinfo returned %d\n", rc); 

     if (rc == 0) 
      freeaddrinfo(res); 

     sleep(1); 
    } 
} 

Prima di eseguire questo programma di test:

  1. Collegarsi alla rete.
  2. Rinomina, temporaneamente /etc/resolv.conf a /etc/resolv.conf.save.
  3. Avvia questo programma di test, utilizzando un buon nome host.
  4. Subito dopo l'avvio del programma di test e la stampa dei codici di errore, rinominare /etc/resolv.conf.save in /etc/resolv.conf.
  5. Osservare che il programma di test sta ancora segnalando errori di risoluzione DNS.
  6. Se si CTRL-C e si riavvia, il programma di test ora segnalerà una risoluzione DNS valida.

Quando si disconnette e si riconnette dalla rete, lo stack di rete riscrive e aggiorna di conseguenza /etc/resolv.conf. Questo file di configurazione è necessario per il resolver DNS nella libreria C. La libreria C legge la configurazione DNS da /etc/resolv.conf la prima volta e la memorizza nella cache. Non controlla, ad ogni ricerca, se il contenuto di /etc/resolv.conf è stato modificato.

Infine:

  1. Il vostro compito a casa è quello di aggiungere una chiamata a res_init(), definito in resolv.h, a questo programma di test, leggere la pagina man corrispondente e vedere cosa succede. Questa è la tua risposta.
+0

Con ciò intendevo res_init() all'interno del ciclo. –

+0

A volte funziona (ma piuttosto di rado). Suppongo che funzioni se la connessione di rete è già stata stabilita, ma 'resolv.conf' non è stato ancora aggiornato quando l'applicazione viene avviata. Una volta che 'resolv.conf' viene aggiornato, la chiamata a' res_init' nel loop carica la nuova configurazione e quindi 'getaddrinfo' supera. Ma se la connessione di rete non è pronta all'avvio dell'applicazione, continua a non riuscire, – kassiopeia

+0

La mia demo dettagliata prevede l'avvio dell'applicazione quando non è configurata alcuna risoluzione DNS, il che sarebbe il caso quando non esistono connessioni di rete. Hai provato ad avviare il codice demo con la chiamata a rs_init() senza una connessione di rete e quindi a collegarti a una rete? Questo breve codice demo è abbastanza semplice da testare. Non c'è bisogno di assumere nulla. –

Problemi correlati