Os soquetes são finalmente fechados pelo kernel do Unix; um programa travado não é diferente de uma saída de programa normal sem uma chamada close()/shutdown()
.
Seu problema pode ter a ver com o estado TIME_WAIT da máquina de estado TCP / IP e deve ser resolvido com a opção SO_REUSEADDR. Uma maneira de confirmar isso é esperar por cerca de 5 minutos antes de começar novamente após uma falha. Se você encontrar soquetes suficientes disponíveis, você deve estudar a lógica TIME_WAIT e contorná-la. Se o truque de espera não resolver seu problema, pode haver um problema diferente no programa que precisa ser identificado.
Aqui está uma boa leitura sobre o assunto,
TIME_WAIT e suas implicações de design para protocolos e sistemas escaláveis de servidores clientes
Dois rápidos extratos de lá para referência,
TIME_WAIT is often also known as the 2MSL wait state. This is because the socket that transitions to TIME_WAIT stays there for a period that is 2 x Maximum Segment Lifetime in duration. The MSL is the maximum amount of time that any segment, for all intents and purposes a datagram that forms part of the TCP protocol, can remain valid on the network before being discarded. This time limit is ultimately bounded by the TTL field in the IP datagram that is used to transmit the TCP segment. Different implementations select different values for MSL and common values are 30 seconds, 1 minute or 2 minutes. RFC 793 specifies MSL as 2 minutes and Windows systems default to this value but can be tuned using the TcpTimedWaitDelay registry setting.
(PS: daí a espera de 4+1
minuto para o meu teste sugerido acima)
Changing the 2MSL delay is usually a machine wide configuration change. You can instead attempt to work around TIME_WAIT at the socket level with the SO_REUSEADDR socket option. This allows a socket to be created whilst an existing socket with the same address and port already exists. The new socket essentially hijacks the old socket. You can use SO_REUSEADDR to allow sockets to be created whilst a socket with the same port is already in TIME_WAIT but this can also cause problems such as denial of service attacks or data theft.
O artigo descreve mais uma maneira. Mas isso vem com outras advertências.
There's another way to terminate a TCP connection and that's by aborting the connection and sending an RST rather than a FIN. This is usually achieved by setting the SO_LINGER socket option to 0. This causes pending data to be discarded and the connection to be aborted with an RST rather than for the pending data to be transmitted and the connection closed cleanly with a FIN. It's important to realise that when a connection is aborted any data that might be in flow between the peers is discarded and the RST is delivered straight away; usually as an error which represents the fact that the "connection has been reset by the peer". The remote peer knows that the connection was aborted and neither peer enters TIME_WAIT.
Antes de usar esses esquemas, é uma boa idéia entender o comportamento da máquina TCP, para que você não introduza inadvertidamente outras situações que precisarão ser depuradas posteriormente. Então, pelo menos leia esse artigo completamente :-)