socket.shutdown vs socket.close

122

Recentemente, vi um pouco de código parecido com este (com a meia sendo um objeto de soquete, é claro):

sock.shutdown(socket.SHUT_RDWR)
sock.close()

Qual é exatamente o objetivo de encerrar o soquete e depois fechá-lo? Se isso faz diferença, esse soquete está sendo usado para E / S sem bloqueio.

Jason Baker
fonte

Respostas:

38

Aqui está uma explicação :

Uma vez que um soquete não é mais necessário, o programa de chamada pode descartá-lo aplicando uma sub-rotina próxima ao descritor de soquete. Se um soquete de entrega confiável tiver dados associados a ele quando um fechamento ocorrer, o sistema continuará tentando a transferência de dados. No entanto, se os dados ainda não forem entregues, o sistema descartará os dados. Se o programa aplicativo não for utilizado para nenhum dado pendente, ele poderá usar a sub-rotina de desligamento no soquete antes de fechá-lo.

Bob Nadler
fonte
241

Chamando closee shutdowntem dois efeitos diferentes no soquete subjacente.

A primeira coisa a salientar é que o soquete é um recurso no SO subjacente e vários processos podem ter um identificador para o mesmo soquete subjacente.

Quando você o chama close, diminui a contagem de identificadores em um e se a contagem de identificadores atingiu zero, o soquete e a conexão associada passam pelo procedimento de fechamento normal (enviando efetivamente um FIN / EOF para o par) e o soquete é desalocado.

O que devemos prestar atenção aqui é que, se a contagem de identificadores não atingir zero, porque outro processo ainda possui um identificador no soquete, a conexão não será fechada e o soquete não será desalocado.

Por outro lado, solicitar shutdownleitura e gravação fecha a conexão subjacente e envia um FIN / EOF para o par, independentemente de quantos processos possuam identificadores para o soquete. No entanto, ele não desaloca o soquete e você ainda precisa ligar mais tarde.

Robert S. Barnes
fonte
grande resposta, eu nunca se preocupou em descobrir o que shutdown()faz :)
Matt Joiner
2
Um shutdown () para leitura faz com que ele envie um pacote FIN? ou seja, desligamento (sock_fd, 1);
ernesto 12/02
Seria inteligente sempre ligar .shutdown()e na próxima linha .close()? Ou deve haver um atraso no meio?
Luc
@ Luc Depende completamente do que você está fazendo.
Robert S. Barnes
2
@ Luc Depois fechar é bom, desde que nenhum outro processo tenha um identificador para o soquete.
Robert S. Barnes
17

Explicação do encerramento e fechamento: Encerramento gracioso (msdn)

O desligamento (no seu caso) indica para a outra extremidade da conexão que não há mais intenção de ler ou gravar no soquete. Em seguida, feche libera qualquer memória associada ao soquete.

A omissão do desligamento pode fazer com que o soquete permaneça na pilha dos sistemas operacionais até que a conexão seja fechada normalmente.

Na IMO, os nomes 'shutdown' e 'close' são enganosos, 'close' e 'destroy' enfatizam suas diferenças.

Dale Reidy
fonte
Não indica para o outro lado que não há mais intenção de ler. O desligamento para leitura não envia nada para o par.
Marquês de Lorne #
7

isso é mencionado diretamente no Socket Programming HOWTO ( py2 / py3 )

Desconectando

A rigor, você deveria usar shutdownum soquete antes de usá - closelo. O shutdowné um aviso para o soquete na outra extremidade. Dependendo do argumento que você aprovar, pode significar “ Não vou mais enviar, mas continuarei ouvindo ” ou “ Não estou ouvindo, boa viagem! ”. A maioria das bibliotecas de soquetes, no entanto, é tão usada por programadores que não usam essa etiqueta que normalmente a closeé a mesma que shutdown(); close(). Portanto, na maioria das situações, um desligamento explícito não é necessário.

...

mykhal
fonte
Esta informação não está correta. Só é necessário desligar um soquete para escrever se (1) você bifurcou o processo e definitivamente deseja enviar o FIN agora, ou (2) você está envolvido em um protocolo de leitura para EOS mútuo, de modo que ambos os pares fechem ao mesmo tempo. Caso contrário, close()é suficiente. A documentação do Python deve ser corrigida.
Marquês de Lorne #
4

Esse código acima não está errado?

A chamada de fechamento diretamente após a chamada de encerramento pode fazer com que o kernel descarte todos os buffers de saída de qualquer maneira.

De acordo com http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-ou-why-is-my-tcp-not-reliable, é preciso esperar entre o desligamento e o fecha até que a leitura retorne 0.

cristão
fonte
Incorreto. O kernel descartará os buffers de saída apenas se a conexão for redefinida, o que pode acontecer se o aplicativo local não ler todos os dados de entrada pendentes que já chegaram ou se o ponto tiver mexido com SO_LINGER, o que eles não devem fazer . Também não há necessidade de dormir, nem mesmo de desligar antes de fechar. Há muita desinformação por aí sobre esse assunto.
Marquês de Lorne
1

Shutdown (1), força o soquete no a enviar mais dados

Isso é útil em

1- Lavagem do tampão

2- Detecção de erro estranho

3- Proteção segura

Deixe-me explicar mais: quando você envia dados de A para B, não é garantido que ele seja enviado para B, apenas para o buffer A, que por sua vez os envia para o buffer OS

Então, chamando shutdown (1) em A, você libera o buffer de A e um erro é gerado se o buffer não estiver vazio, ou seja: os dados ainda não foram enviados para o par

No entanto, isso é irrecuperável, para que você possa fazer isso depois de enviar todos os seus dados completamente e desejar ter certeza de que estão no buffer do sistema operacional de mesmo nível

user306166
fonte
O desligamento não força uma descarga. A situação do buffer é inalterada. E se o buffer não estiver vazio, nenhum erro será gerado. O FIN é enfileirado atrás dos dados pendentes. A resposta está completamente incorreta.
Marquês de Lorne #