Search code examples
c#windowssockets

Can Client use the same Socket object to reconnect to remote after disconnect


Maybe the simple answer is no, a new socket object must be created each time... but my situation is.

  1. Client creates socket and uses ConnectAsync to connect to remote server
  2. ConnectAsync Completed event runs and Connection starts
  3. Connection to Server is forcibly severed (SocketException)
  • [Unattainable? GOAL] Reconnect to the server using the same Socket object

I know using socket.close() and then recreating the socket allows me to reconnect the server. But is that cleanest/proper way of reconnecting to the server and why? Otherwise is there a better/proper way to reconnect using the same socket?

I have searched Stackoverflow and google all over the place and the closest I got was that a reconnect is possible with a different endpoint which doesnt fit my usecase.

I have tried the following

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
connectArgs.RemoteEndPoint = new IPEndPoint(myIP, myPortNo);
connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ConnectCallback);
socket.ConnectAsync(connectArgs);

... After Forcibly Disconnected

// This does not get run because the forcibly connection cut exception sets Connected to false. 
// And Shutdown/Disconnect will throw an exception if the socket is not Connected.
if (socket.Connected) 
{
  socket.Shutdown(SocketShutdown.Both);
  socket.Disconnect(true); // this is the reuse bool property.
}
// socket.close() // calling this disposes the object, can no longer connect with it again so this is also out

socket.ConnectAsync(connectArgs); //<- immediately returns false

Is there a way to gracefully reset this socket object without resetting to a new socket instance so that I can use the ConnectAsync command again and have it work like the first time?


Solution

  • No, the socket cannot be reused after a connection abort (a RST packet or a network failure). You need to close the socket and open a new one.

    The WinSock docs state that if a connection reset error occurs then the socket is unusable.

    WSAECONNRESET: The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a UPD-datagram socket this error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message.

    Also:

    WSAECONNRESET: Connection reset by peer.
    An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET.

    The only time you can reuse a socket after the connection has ended is if you use Disconnect/DisconnectAsync, this is not normal usage.

    I strongly suggest you use TcpClient instead of raw sockets, as that can manage all the connecting and closing of sockets for you. Or even an existing higher level protocol, such as HTTP, gRPC or SignalR, because writing a TCP protocol is fraught with pitfalls.