2009-04-11 11 views
6

Quando si utilizza un socket TCP, ciò faComportamento di arresto (calzino, SHUT_RD) con TCP

shutdown(sock, SHUT_RD); 

effettivamente fare? Fa semplicemente restituire un codice di errore a tutte le chiamate recv()? Se sì, quale codice di errore?

Fa sì che i pacchetti vengano inviati dalla connessione TCP sottostante? Ciò che accade a tutti i dati che l'altro lato invia a questo punto - è mantenuto, e la dimensione della finestra della connessione continua a ridursi fino a quando non arriva a 0, o viene semplicemente scartata e la dimensione della finestra non si riduce?

risposta

4

La chiusura del lato di lettura di una presa causerà chiamate bloccate recv (o simili) per restituire 0 (indicando un arresto regolare). Non so cosa accadrà ai dati che stanno attualmente viaggiando nello stack IP. Sicuramente ignorerà i dati che sono in volo dall'altra parte. Non influenzerà affatto le scritture su quel socket.

In effetti, l'uso giudizioso di shutdown è un buon modo per assicurarti di eseguire la pulizia non appena hai finito. Un client HTTP che non usa keepalive può arrestare il lato di scrittura non appena viene inviata la richiesta, e un server che vede può anche arrestare il lato di lettura non appena ha finito di ricevere la richiesta. Ciò causerà immediatamente un'eventuale attività errata, che è molto utile quando si scrive codice a livello di protocollo.

2

Guardando il codice sorgente di Linux, shutdown(sock, SHUT_RD) non sembra causare alcun cambiamento di stato nel socket. (Ovviamente, imposta FIN da impostare.)

Non riesco a commentare le modifiche alle dimensioni della finestra (o la sua mancanza). Ma puoi scrivere un programma di prova da vedere. Basta fare il tuo inetd eseguire un servizio chargen e connettersi ad esso. :-)

0

shutdown (calzino, SHUT_RD) fa sì che qualsiasi scrittore sul socket riceva un segnale sigpipe.

Qualsiasi ulteriore lettura mediante la chiamata di sistema di lettura restituirà -1 e imposterà errno su EINVAL.

L'uso di recv restituirà un -1 e imposta errno per indicare l'errore (probabilmente ENOTCONN o ENOTSOCK).

+0

perché SHUT_RD influisce sugli autori? Non vedo alcuna ragione ovvia per farlo (anche se, suppongo che io usi sempre MSG_NOSIGNAL, in modo che possa avere un impatto). – Tom

+0

Perché (citando da Wikipedia) "Sulle piattaforme conformi a POSIX, SIGPIPE è il segnale inviato a un processo quando tenta di scrivere su una pipe senza un processo collegato all'altro capo." E l'istruzione shutdown (calzino, SHUT_RD) disconnette il processo del lettore dalla pipe. Per aggiungere lesioni a insulti, l'azione predefinita al ricevimento di un segnale SIGPIPE è per il processo (cioè lo scrittore) di terminare. –

+0

Questo non è corretto. Qualsiasi ulteriore lettura causerà recv() per rieseguire lo zero, indicando la fine del flusso. – EJP

3

shutdown (, SHUT_RD) non ha alcuna controparte nel protocollo TCP, quindi è praticamente l'implementazione come comportarsi quando qualcuno scrive su una connessione dove l'altro lato indica che non leggerà o quando si tenta di leggere dopo aver dichiarato che non lo farai.

Su un livello leggermente inferiore è utile ricordare che la connessione TCP è una coppia di flussi che utilizzano i peer per inviare dati finché non dichiarano di essere eseguiti (da SHUT_WR che invia FIN). E questi due flussi sono abbastanza indipendenti.

0

Ha due effetti, uno dei quali dipende dalla piattaforma.

  1. recv() restituisce zero, che indica la fine del flusso.
  2. Qualsiasi ulteriore scrittura alla connessione da parte del peer sarà (a) silenziata via dal ricevitore (BSD), (b) essere bufferizzata dal ricevitore e infine causare send() per bloccare o restituire -1/EAGAIN/EWOULDBLOCK (Linux) o (c) fa in modo che il destinatario invii un RST (Windows).
1

I test shudown(sock,SHUT_RD) su Ubuntu 12.04. Trovo che quando si chiama shutdown(sock,SHUT_RD) se non ci sono nessun tipo di dati (include FIN ....) nel buffer TCP, la successiva chiamata di lettura sarà return 0 (indica la fine del flusso). Ma se ci sono dati che arrivano prima o dopo la funzione di spegnimento, la chiamata di lettura verrà elaborata normalmente come se la funzione di spegnimento non venisse chiamata. Sembra che shutdown(sock,SHUT_RD) non causi la modifica degli stati TCP al socket