2012-03-13 16 views
10

Voglio essere in grado di interrompere l'ascolto su un socket del server in linux e assicurare che tutte le connessioni aperte dal punto di vista di un client siano gestite correttamente e non chiuse bruscamente (es .: ricevi ECONNRESET) .Presa server di spegnimento di Graceful in Linux

cioè:

sock = create_socket(); 
listen(sock, non_zero_backlog); 
graceful_close(sock); 

se il pensiero di chiamare close() e movimentazione prese già accept'd sarebbe sufficiente, ma ci possono essere collegamenti che sono aperti nel portafoglio ordini del kernel che verrà bruscamente chiuso se si chiama vicino() sul socket del server.

+0

Potrebbe essere possibile farlo con ['shutdown'] (http://linux.die.net/man/2/shutdown). Non l'ho ancora provato, quindi non so se funzionerà. –

+0

Non penso che ci sia un modo per farlo. Dai un'occhiata alla coda della discussione qui: http://fixunix.com/networking/535700-disonnecting-tcp-listening-socket.html – Nick

+2

@drscroogemcduck, per favore, definisci cosa intendi con "correttamente". Ottenere un RST per una connessione TCP semiaperta * è * corretto, da RFC. – tbert

risposta

5

L'unico modo di lavoro per farlo (che ho trovato) è quello di:

  1. prevenire accept() di aggiungere più clienti

  2. avere una lista dei socket aperti da qualche parte e aspettare fino a sono tutti ben chiuso il che significa:

    • utilizzando shutdown() per dire al cliente che non sarà più lavorare su quel socket

    • chiamata read() per un po 'per assicurarsi che tutto il cliente ha inviato frattempo è stato tirato

    • quindi utilizzando close() per liberare ogni cliente presa.

  3. ALLORA, si può tranquillamente close() il socket di ascolto.

È possibile (e necessario) utilizzare un timeout per assicurarsi che le connessioni inattive non durino per sempre.

+0

SO_REUSEADDR sembra essere una soluzione decente su socket locali, probabilmente è ancora la soluzione migliore per uscire in modo pulito ma potrebbe non essere possibile in tutte le situazioni. –

2

Si sta osservando una limitazione dell'API socket TCP. È possibile controllare ECONNRESET come versione socket di EOF oppure, è possibile implementare un protocollo di livello superiore su TCP che informa il client di una disconnessione imminente.

Tuttavia, se si tenta la seconda alternativa, tenere presente dell'intrattabile Two Armies Problem che rende impossibile l'arresto regolare nel caso generale; questo è parte della motivazione per il meccanismo di reset della connessione TCP così com'è. Anche se potessi scrivere graceful_close() in un modo che ha funzionato la maggior parte del tempo, probabilmente dovresti ancora occuparti di ECONNRESET a meno che il processo del server non possa attendere per sempre di ricevere un graceful_close_ack dal client.

Problemi correlati