Nenhuma das respostas existentes informa às pessoas como shutdown
e close
funciona no nível do protocolo TCP, portanto, vale a pena adicionar isso.
Uma conexão TCP padrão é finalizada pela finalização em quatro direções:
- Uma vez que um participante não tem mais dados para enviar, envia um pacote FIN para o outro
- A outra parte retorna um ACK para o FIN.
- Quando a outra parte também conclui a transferência de dados, envia outro pacote FIN
- O participante inicial retorna um ACK e finaliza a transferência.
No entanto, existe outra maneira "emergente" de fechar uma conexão TCP:
- Um participante envia um pacote RST e abandona a conexão
- O outro lado recebe um RST e depois abandona a conexão também
No meu teste com o Wireshark, com opções de soquete padrão, shutdown
envia um pacote FIN para a outra extremidade, mas é tudo o que faz. Até que a outra parte envie o pacote FIN, você ainda poderá receber dados. Quando isso acontecer, você Receive
obterá um resultado de tamanho 0. Portanto, se você é o primeiro a desligar o "send", feche o soquete assim que terminar de receber os dados.
Por outro lado, se você ligar close
enquanto a conexão ainda estiver ativa (o outro lado ainda está ativo e você também pode ter dados não enviados no buffer do sistema), um pacote RST será enviado para o outro lado. Isso é bom para erros. Por exemplo, se você acha que a outra parte forneceu dados incorretos ou se recusou a fornecer dados (ataque do DOS?), Você pode fechar o soquete imediatamente.
Minha opinião sobre as regras seria:
- Considere
shutdown
antes, close
quando possível
- Se você terminou de receber (dados de tamanho 0 recebidos) antes de decidir encerrar, feche a conexão após o término do último envio (se houver).
- Se você deseja fechar a conexão normalmente, encerre a conexão (com SHUT_WR e se você não se importa em receber dados após esse ponto, com SHUT_RD também), aguarde até receber um tamanho de 0 e feche o tomada.
- De qualquer forma, se ocorreu algum outro erro (tempo limite, por exemplo), basta fechar o soquete.
Implementações ideais para SHUT_RD e SHUT_WR
O seguinte não foi testado, confie em seu próprio risco. No entanto, acredito que essa é uma maneira razoável e prática de fazer as coisas.
Se a pilha TCP receber um desligamento apenas com SHUT_RD, marcará essa conexão como não há mais dados esperados. Quaisquer read
solicitações pendentes e subseqüentes (independentemente do segmento em que estão) serão retornadas com resultado de tamanho zero. No entanto, a conexão ainda está ativa e utilizável - você ainda pode receber dados OOB, por exemplo. Além disso, o sistema operacional eliminará todos os dados que receber para esta conexão. Mas isso é tudo, nenhum pacote será enviado para o outro lado.
Se a pilha TCP receber um desligamento apenas com SHUT_WR, marcará essa conexão como não mais dados podem ser enviados. Todas as solicitações de gravação pendentes serão concluídas, mas as solicitações de gravação subsequentes falharão. Além disso, um pacote FIN será enviado para outro lado para informar que não temos mais dados para enviar.