Controlla questo link
http://www.toptip.ca/2010/02/linux-eaddrnotavail-address-not.html
MODIFICA :Sì, volevo aggiungere altro, ma ho dovuto tagliarlo a causa di un'emergenza
Hai chiuso la presa prima di provare a riconnetterti? La chiusura dirà al sistema che la coppia di socket (ip/porta) è ora libera.
Qui ci sono anche altri elementi da guardare:
- Se la porta locale è già connessa all'IP e alla porta remoti indicati (ovvero, esiste già una coppia di socket identica), riceverai questo errore (vedi il link al bug di seguito).
- L'associazione di un indirizzo socket diverso da quello locale produrrà questo errore. se gli indirizzi IP di una macchina sono 127.0.0.1 e 1.2.3.4 e stai tentando di collegarti a 1.2.3.5, otterrai questo errore.
- EADDRNOTAVAIL:l'indirizzo specificato non è disponibile sulla macchina remota o il campo dell'indirizzo della struttura del nome è tutto zero.
Collegamento con un bug simile al tuo (la risposta è quasi in fondo)
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4294599
Sembra che il tuo socket sia sostanzialmente bloccato in uno degli stati interni del TCP e che l'aggiunta di un ritardo per la riconnessione potrebbe risolvere il tuo problema come sembra che abbiano fatto in quella segnalazione di bug.
Se non sei disposto a modificare il numero di porte temporanee disponibili (come suggerito da David), o hai bisogno di più connessioni rispetto al massimo teorico, ci sono altri due metodi per ridurre il numero di porte in uso. Tuttavia, sono a vari livelli violazioni dello standard TCP, quindi dovrebbero essere usati con cautela.
Il primo è attivare SO_LINGER
con un timeout di zero secondi, forzando il TCP
stack per inviare un pacchetto RST e svuotare lo stato della connessione. C'è una sottigliezza, tuttavia:dovresti chiamare shutdown
sul descrittore di file socket prima di close
, in modo da avere la possibilità di inviare un FIN
pacchetto prima del RST
pacchetto. Quindi il codice sarà simile a:
shutdown(fd, SHUT_RDWR);
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 0;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_LINGER,
(char *) &linger, sizeof(linger));
close(fd);
Il server dovrebbe vedere una connessione prematura reimpostata solo se FIN
pacchetto viene riordinato con RST
pacchetto.
Vedere l'opzione TCP SO_LINGER (zero) - quando è richiesta per maggiori dettagli. (Sperimentalmente, non sembra importare dove imposti setsockopt
.)
Il secondo è usare SO_REUSEADDR
e un bind
esplicito (anche se sei il client), che consentirà a Linux di riutilizzare le porte temporanee durante l'esecuzione, prima che finiscano di aspettare. Nota che devi usa bind
con INADDR_ANY
e la porta 0
, altrimenti SO_REUSEADDR
non è rispettato. Il tuo codice sarà simile a:
int opts = 1;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &opts, sizeof(int));
struct sockaddr_in listen_addr;
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = 0;
listen_addr.sin_addr.s_addr = INADDR_ANY;
// todo: test for error
bind(fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr));
// todo: test for addr
// saddr is the struct sockaddr_in you're connecting to
connect(fd, (struct sockaddr *) &saddr, sizeof(saddr));
Questa opzione è meno valida perché continuerai a saturare le strutture dati interne del kernel per le connessioni TCP come da netstat -an | grep -e tcp -e udp | wc -l
. Tuttavia, non inizierai a riutilizzare le porte fino a quando ciò non accadrà.
Questo può accadere anche se viene fornita una porta non valida, come 0.