socket.shutdown vs socket.close
-
03-07-2019 - |
Domanda
Di recente ho visto un po 'di codice simile a questo (con calzino che è un oggetto socket ovviamente):
sock.shutdown(socket.SHUT_RDWR)
sock.close()
Qual è esattamente lo scopo di chiamare l'arresto sul socket e quindi chiuderlo? Se fa la differenza, questo socket viene utilizzato per IO non bloccanti.
Soluzione
Eccone uno spiegazione :
Quando non è più necessario un socket, il programma chiamante può scartare il socket applicando una subroutine di chiusura al descrittore di socket. Se una presa di consegna affidabile ha dati associato ad esso quando si chiude posto, il sistema continua a tentare trasferimento dati. Tuttavia, se i dati lo sono ancora non consegnato, il sistema scarta i dati. Dovrebbe l'applicazione il programma non ha alcuna utilità per qualsiasi in sospeso dati, può utilizzare l'arresto subroutine sul socket prima di chiudendolo.
Altri suggerimenti
La chiamata di close
e shutdown
ha due effetti diversi sul socket sottostante.
La prima cosa da sottolineare è che il socket è una risorsa nel sistema operativo sottostante e più processi possono avere un handle per lo stesso socket sottostante.
Quando si chiama close
diminuisce il conteggio degli handle di uno e se il conteggio degli handle ha raggiunto lo zero, il socket e la connessione associata passano attraverso la normale procedura di chiusura (inviando effettivamente un FIN / EOF al peer) e il socket è deallocato.
La cosa a cui prestare attenzione qui è che se il conteggio degli handle non raggiunge lo zero perché un altro processo ha ancora un handle per il socket, la connessione non viene chiusa e il socket non viene deallocato.
D'altra parte, chiamando shutdown
per leggere e scrivere si chiude la connessione sottostante e si invia un FIN / EOF al peer indipendentemente da quanti processi hanno handle per il socket. Tuttavia, non disloca il socket e dovrai comunque chiamare in seguito.
Spiegazione di arresto e chiusura: Arresto grazioso (msdn)
L'arresto (nel tuo caso) indica all'altra estremità della connessione che non vi è alcuna ulteriore intenzione di leggere o scrivere sul socket. Quindi close libera tutta la memoria associata al socket.
Se si omette l'arresto, il socket potrebbe rimanere nello stack del sistema operativo fino a quando la connessione non verrà chiusa correttamente.
IMO i nomi 'shutdown' e 'close' sono fuorvianti, 'close' e 'destro' enfatizzerebbero le loro differenze.
è menzionato proprio nel Socket Programming HOWTO ( py2 / < a href = "http://docs.python.org/3/howto/sockets.html#disconnecting" rel = "noreferrer"> py3 )
scollegamento
In senso stretto, dovresti utilizzare
shutdown
su un socket prima dichiudere
. Ilshutdown
è un avviso al socket all'altro capo. A seconda dell'argomento che lo passi, può significare & # 8220; Non invierò più, ma ascolterò ancora & # 8217; ascolterò ancora & # 8221; oppure & # 8220 ; Non sto ascoltando, buon viaggio! & # 8221 ;. La maggior parte delle librerie di socket, tuttavia, sono così usate dai programmatori che trascurano di usare questa etichetta che normalmente unclose
è lo stesso dishutdown (); close ()
. Pertanto, nella maggior parte dei casi, non è necessario un arresto esplicito....
Questo codice sopra non è sbagliato?
La chiamata di chiusura direttamente dopo la chiamata di arresto potrebbe far sì che il kernel scarti comunque tutti i buffer in uscita.
Secondo http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable è necessario attendere tra l'arresto e la chiusura fino a quando la lettura non restituisce 0.
ci sono alcuni tipi di arresto: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx . * nix è simile.
Shutdown (1), impone al socket no di inviare ulteriori dati
Questo è utile in
1- Svuotamento buffer
2- Rilevamento di errori strani
3- Protezione sicura
Lasciami spiegare di più, quando invii un dato da A a B, non è garantito che lo sia inviato a B, è garantito solo per essere inviato al buffer A os, che a sua volta lo invia al buffer di sistema operativo
Quindi chiamando shutdown (1) su A, si cancella il buffer di A e viene generato un errore se il buffer non è vuoto, ovvero: i dati non sono stati ancora inviati al peer
Tuttavia, questo è irreversibile, quindi puoi farlo dopo tutto ha inviato tutti i tuoi dati e vuoi essere sicuro che siano almeno pari buffer os