2012-01-15 1 views
23

È consigliabile/sicuro per close() un socket direttamente dopo l'ultimo send()?close() socket direttamente dopo send(): non sicuro?

So che TCP dovrebbe cercare di recapitare tutti i dati rimanenti nel buffer di invio anche dopo aver chiuso il socket, ma posso davvero contare su questo?

Mi sto assicurando che non ci siano dati rimanenti nel mio buffer di ricezione in modo che nessun RST verrà inviato dopo la mia chiusura.


Nel mio caso, la chiusura è in realtà l'ultima dichiarazione del codice prima di chiamare exit().

Lo stack TCP continuerà effettivamente a provare a trasmettere i dati anche dopo che il processo di invio è terminato? È affidabile come aspettare un timeout arbitrario prima di chiamare close() impostando SO_LINGER?

Cioè, si applicano gli stessi timeout TCP o sono più brevi? Con un grande buffer di invio e una connessione lenta, il tempo per trasferire effettivamente tutti i dati memorizzati nel buffer potrebbe essere sostanziale, dopo tutto.


Non mi interessa affatto ricevere notifica dell'ultimo byte inviato; Voglio solo che alla fine arrivino all'host remoto nel modo più affidabile possibile.

Le conferme del livello applicazione non sono un'opzione (il protocollo è HTTP e sto scrivendo un piccolo server).

+0

Dipende dall'implementazione, ma in generale, sì, un 'close()' svuota tutti i dati rimanenti nel buffer prima che faccia effettivamente a pezzi il socket. Il chilometraggio può variare se si termina l'intero processo oltre a chiamare 'close()'. – aroth

+2

@aroth Il chilometraggio * non * varia se si esce dal processo. Non c'è differenza tra i due casi. Se si desidera mantenere il contrario, fornire un riferimento autorevole. – EJP

+0

@EJP - Un riferimento autorevole su cosa * potrebbe * accadere in programmi arbitrari? Non penso che esista una cosa del genere. Ma è abbastanza semplice dare un esempio plausibile. Supponiamo che tu abbia un programma che delega tutte le operazioni di rete in un thread separato, come dovrebbe fare la maggior parte dei programmi. È possibile che il thread principale termini il processo (con garbo o meno) mentre il thread in background sta chiamando 'close()'. La chiamata riuscirà in tal caso? Ne dubito. Certo, quello che dici dovrebbe essere vero per qualsiasi programma a thread singolo. Ma non tutti i programmi sono a thread singolo. – aroth

risposta

20

Ho letto molto il ultimate SO_LINGER page. Ti raccomando di leggerlo anche tu. Descrive casi limite di trasferimenti di dati di grandi dimensioni per quanto riguarda i socket TCP.

io non sono l'esperto di SO_LINGER, ma sul mio codice del server (ancora in fase di sviluppo) faccio la seguente:

  1. Dopo l'ultimo byte viene inviato tramite send(), che io chiamo " shutdown (sock, SHUT_WR) "per attivare un FIN da inviare.

  2. Quindi attendere una successiva chiamata recv() su quel socket per restituire 0 (o recv restituisce -1 e errno è qualsiasi altra cosa EAGAIN/EWOULDBLOCK).

  3. Quindi il server esegue una chiusura() sul socket.

L'assunto è che il client chiuderà il socket dopo aver ricevuto tutti i byte della risposta.

Ma ho applicato un timeout tra l'invio finale() e quando recv() indica EOF. Se il client non chiude mai la sua estremità della connessione, il server si arrenderà e comunque chiude la connessione. Sono a 45-90 secondi per questo timeout.

Tutti i miei socket sono non bloccanti e utilizzo poll/epoll per ricevere notifiche sugli eventi di connessione come suggerimento per vedere se è il momento di provare a chiamare nuovamente recv() o send().

+2

Sembra una soluzione molto buona se il client chiude prima il socket. Tuttavia, non potrebbe forse chiudere la sua metà della connessione immediatamente dopo aver inviato la richiesta? Le specifiche HTTP non dicono nulla in materia di mezze chiusure; pensi che questo comportamento si verifichi mai nei client HTTP? – lxgr

+0

No. Ho fatto alcuni annodi wirehark ad hoc per convalidare. Ti incoraggio a fare lo stesso. Dal mio test di sniffing dei pacchetti - a volte il server invia la sua FIN dopo la risposta e il client invia FIN dopo aver ricevuto la risposta. Ma la maggior parte dei client http specifica comunque l'opzione "keep-alive" con il server, quindi i client non avviano comunque una chiusura. In altre parole, penso che sia molto sicuro assumere che i clienti non facciano una mezza stretta. – selbie

+0

Inoltre, i clienti probabilmente prestano attenzione all'intestazione Content-Length. Può essere plausibile che il server non abbia bisogno di chiudere o spegnere dopo aver inviato tutti i suoi byte, perché il client sa quanti byte aspettarsi nel HTTP resposne. (E il server sicuramente non si chiuderà se supporta la connessione keep-alive e se il client lo richiede). Ma in richieste più semplici senza keep-alive, il server invia una FIN dopo che la sua risposta è stata inviata. – selbie