2009-05-22 14 views
12

Attualmente sto mantenendo alcuni software per server Web e ho bisogno di eseguire molte operazioni di I/O. Le chiamate read(), , close() e shutdown(), se utilizzate su un socket, possono talvolta generare un errore ENOTCONN. Cosa significa esattamente questo errore? Quali sono le condizioni che l'avrebbero innescata? Non riesco mai a riprodurlo localmente ma ci sono utenti che possono farlo.Che cosa causa l'errore ENOTCONN?

In questo momento ho appena ignorato ENOTCONN quando generato da close() e shutdown() perché sembra innocuo, ma non ne sono del tutto sicuro.

EDIT:

  • Sono assolutamente sicuro che la chiamata è riuscita connect(). Controllo il suo valore di ritorno.
  • ENOTCONN viene generato più spesso da close() e shutdown(). Ho visto molto raramente un aumento di read() e write()ENOTCONN.
+0

Quale sistema operativo? Sto rintracciando un problema simile al lavoro su un vecchio sistema Solaris 10. Grazie. – Nemo

+0

Per lo più FreeBSD.Nel frattempo ho scoperto che ci sono bug del kernel in FreeBSD che potrebbero causare close() e shutdown() per restituire ENOTCONN erroneamente quando si ha a che fare con socket di dominio Unix. Solaris ha anche vari bug del kernel w.r.t. Socket di dominio Unix, anche se ho solo osservato bug in connect(). – Hongli

risposta

13

Se si è certi che nulla dalla propria parte della connessione TCP stia chiudendo la connessione, mi sembra che il lato remoto stia chiudendo la connessione.

ENOTCONN, come altri hanno sottolineato, significa semplicemente che la presa non è collegata. Questo non significa necessariamente che connect non sia riuscito. Il socket potrebbe essere stato collegato in precedenza, ma non era al momento della chiamata che ha provocato ENOTCONN.

Ciò differisce da:

  • ECONNRESET: l'altra estremità della connessione inviato un pacchetto TCP reset. Questo può accadere se l'altra estremità rifiuta una connessione, o non riconosce che è già connessa, tra le altre cose.
  • ETIMEDOUT: generalmente si applica solo a connect. Questo può accadere se il tentativo di connessione non ha esito positivo in un lasso di tempo dipendente dal sistema.

EPIPE volte può essere restituito da qualche sistema presa legati chiamate in condizioni che sono più o meno lo stesso come ENOTCONN.Ad esempio, su alcuni sistemi, EPIPE e ENOTCONN sono anche restituiti da send.

Anche se non è insolito per shutdown per tornare ENOTCONN, dal momento che questa funzione dovrebbe abbattere la connessione TCP, sarei sorpreso di vedere close ritorno ENOTCONN. Non dovrebbe mai farlo.

Infine, come accennato DWC, EBADF non dovrebbe applicarsi nello scenario a meno che non si sta tentando alcune operazioni su un descrittore di file che è già stato close d. Avere un socket disconnesso (ovvero la connessione TCP è interrotta) non equivale a chiudere il descrittore di file associato a quel socket.

+0

Ti stai sbagliando: l'altro lato che chiude la connessione non è un motivo per cui shutdown() o close() falliscono. Né un ENOTCONN su shutdown() indica che nessun RESET è realmente avvenuto nella realtà. (Vedi la mia risposta per maggiori dettagli.) –

+0

@Robert: Non penso di averlo detto. Vedo solo che ho detto che 'ENOTCONN' può essere restituito da' shutdown' (che è assolutamente vero) e che non dovrebbe mai essere restituito da 'close', come l'OP stava dicendo che aveva osservato (anche assolutamente vero) . –

+0

Si dice entrambi, che ENOTCONN è stato restituito perché il lato remoto ha chiuso la connessione _ e_ che è diverso da ECONNRESET. - Dico che ENOTCONN non viene mai restituito per una normale connessione remota. Credo inoltre che le implementazioni shutdown() possano restituire ENOTCONN nei casi ECONNRESET, perché non si suppone che quest'ultimo restituisca shutdown(). –

0

Transport endpoint non è collegato

La presa è associata ad un protocollo orientato alla connessione e non è stato collegato. Questo è di solito un difetto di programmazione.

Da: http://www.wlug.org.nz/ENOTCONN

+1

Conosco il nome dell'errore, ma cosa significa * *? Qual è l'endpoint del trasporto a cui si riferisce e in che modo è diverso da EPIPE, ECONNRESET e ETIMEDOUT? – Hongli

+0

Immagino che non abbiate chiamato connect() o che non abbiate controllato se connect() ha avuto successo. –

+0

L'ho fatto, ci è riuscito. Gli utenti che hanno segnalato questo problema hanno osservato che le funzioni read() e write() funzionano correttamente, ma al momento di shutdown() e close() aumentano ENOTCONN. Non riesco a riprodurlo localmente e la maggior parte degli utenti non ha riscontrato questo problema. – Hongli

0

Se sei sicuro di aver collegato correttamente, in primo luogo, ENOTCONN è più probabile essere causato sia dal fd essendo chiuso da parte vostra, mentre (forse in un altro thread?) sei nel bel mezzo di una richiesta o quando la connessione si interrompe mentre sei nel mezzo della richiesta.

In ogni caso, significa che la presa non è collegata. Vai avanti e ripulisci quella presa. È morto. Nessun problema chiamando close() o shutdown() su di esso.

+0

Sono abbastanza sicuro che il file non venga chiuso da un altro thread. Ma supponiamo di sì, non provocherebbe invece un EBADFD? Inoltre, è spesso close() e shutdown() che sollevano ENOTCONN, non read() e write(). Cosa significherebbe? – Hongli

+0

Nella mia risposta specificherò "nel mezzo di una richiesta". Quindi si effettua la chiamata e l'esecuzione passa a un altro processo. Quindi la connessione si interrompe e il processo inizia ad essere eseguito ... EBADFD non era e non è vero (è un file fd valido), ma non sei connesso. Quindi ottieni ENOTCONN. – dwc

1

Credo che ENOTCONN venga restituito, perché shutdown() non dovrebbe restituire ECONNRESET o altri errori più precisi.

È sbagliato supporre che l'altro lato "solo" abbia chiuso la connessione. A livello TCP, l'altra parte può solo chiudere a metà una connessione (o interromperla). La connessione è ordinaria completamente chiusa se entrambe le parti eseguono uno shutdown() (o close()). Se entrambe le parti lo fanno, shutdown() riesce effettivamente per entrambi!

Il problema è che l'arresto() ha non riuscire a ordinaria (mezza) chiudere la connessione, né come il primo per chiuderla, né come il secondo. - Dagli errori elencati nei documenti POSIX per shutdown(), ENOTCONN è il meno appropriato, poiché gli altri indicano problemi con argomenti passati a shutdown() (o problemi di risorse locali per gestire la richiesta).

Quindi cosa è successo? Al giorno d'oggi, un dispositivo NAT tra le due parti coinvolte potrebbe aver abbandonato l'associazione e inviato i pacchetti RESET come reazione. Le connessioni di reset sono così comuni per IPv4, che le si ottiene ovunque nel codice, anche mascherate come ENOTCONN in shutdown().

Un bug di codifica potrebbe essere il motivo. Ad esempio, su un socket non bloccante, connect() può restituire 0 senza indicare ancora una connessione riuscita.

+0

È già stato confermato un bug del kernel di FreeBSD. Il codice di errore ENOTCONN è stato osservato su socket di dominio Unix, quindi TCP non poteva avere nulla a che fare con esso comunque. – Hongli

+0

Ho trovato la tua domanda mentre cercavo i motivi per cui ENOTCONN viene restituito mentre funziona su un socket TCP collegato in precedenza. (Non era il tuo caso, ma la domanda è ancora nell'aria.) - E mi sono sentito in dovere di rispondere perché il motivo è: un bug (kernel) da qualche parte o una condizione di errore della connessione, che è etichettata in modo inappropriato ENOTCONN. Il motivo è ed è stato _non_ una normale connessione remota chiusa. Questa risposta è errata per entrambi i socket di dominio unix (il tuo caso) e socket TCP (il mio caso). –

1

E 'perché, al momento dello shut() del socket, si hanno dati nel buffer del socket in attesa di essere consegnati alla parte remota che ha chiuso() o spento() il suo socket di ricezione. Non ho finito di capire come funzionano i socket, sono piuttosto un noob, e non ho nemmeno trovato i file dove è implementata questa funzione di "shutdown", ma visto che praticamente non c'è un manuale utente per l'intera cosa ho iniziato a provare tutte le possibilità fino a quando ho ottenuto l'errore in un ambiente "controllato". Potrebbe essere qualcosa di diverso, ma dopo molto cercare queste sono le spiegazioni ho optato per:

  • Se hai inviato i dati dopo il lato remoto ha chiuso la connessione, quando si shutdown(), si ottiene l'errore.
  • Se hai inviato dati prima che il lato remoto abbia chiuso la connessione ma non sia stato ricevuto() dall'altra parte, puoi spegnere() una volta, la volta successiva che provi a shutdown(), ottieni l'errore.
  • Se non si sono inviati dati, è possibile arrestare tutte le volte che si desidera, a condizione che il lato remoto non si spenga(); una volta che il lato remoto ha shutdown(), se si tenta di shutdown() e il socket era già shutdown(), si ottiene l'errore.
Problemi correlati