0

I use this code to reset a socket when I get an error sending or receiving.

try {
  socket.Shutdown(SocketShutdown.Both);
  socket.Close();
  socket.Dispose(); 
} catch(Exception) {
}
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ep)

I want to know if I can skip Shutdown, Close, and Dispose so I can get reconnected faster? The garbage collector will eventually call those, right?

johnnycrash
  • 5,184
  • 5
  • 34
  • 58
  • Are you sure those methods are taking appreciable time to run? – Nate Barbettini Sep 25 '17 at 23:05
  • If you want something faster (but I can't see any benefit on this, some milliseconds will make no difference at all), copy the reference to the old socket, create the new socket, connect and then destroy the old one. You will not get anything faster than that. – Gusman Sep 25 '17 at 23:10
  • *"the garbage collector will eventually call those, right?"* - nope – James Sep 25 '17 at 23:10
  • @Nate I've read a lot of comments and questions all over stack overflow that imply these might block in certain cases. Sometimes these block for minutes. – johnnycrash Sep 25 '17 at 23:28
  • @James the garbage collector will call Dispose(), and that probably calls some sort of shutdown? – johnnycrash Sep 25 '17 at 23:29
  • 3
    @johnnycrash *"the garbage collector will call Dispose()"* - a common [misconception](https://stackoverflow.com/questions/45036/will-the-garbage-collector-call-idisposable-dispose-for-me). – James Sep 25 '17 at 23:37

1 Answers1

1

Your question suggests you have some misunderstanding about how to use sockets.

The Shutdown() method is not the same as the Close() method. They both are required. The Shutdown() method is what you use to inform the remote endpoint that you're done sending. Once both ends have shutdown the socket, then you can close the socket. Not before.

The Close() method is there to free up the unmanaged resources, i.e. the Windows socket handle that the .NET Socket class abstracts. Call this method only after you have gracefully shutdown the connection, or after an exception occurs while using the socket (at which point, the socket is no longer usable).

You don't need to call Dispose() at all. All it does is call the Close() method. Alternatively, call Dispose() instead of calling Close(). Either is fine. You don't need to call both.

It is true that if you call neither Close() nor Dispose(), at some point the garbage collector might get around to finalizing the object, which will dispose it for you. But that's not guaranteed, not when it will happen nor even if it will ever happen.

Note that if you want to reconnect faster, you need to do the graceful shutdown, even though it seems like that's more work. If you just close the socket, or you close it after calling Shutdown() but before waiting for the remote endpoint to also shutdown the connection, your socket will wind up in a waiting state that prevents reuse of that port and socket resources. The fastest way to reset your connection state and get reconnected again is to use the API correctly.

I always recommend to people new to the socket API to read the Winsock Programmer's FAQ. It's not written for the .NET audience, but almost all of the information there is critically useful to anyone trying to learn how to use any network socket API.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • I'm going to read the FAQ, thanks. I use the socket to connect to Redis. The code is async so only one socket handles millions of msgs an hour. Occasionally the connection hiccups. I get an error sending or receiving. I can create a new socket object, connect it, and continue. I am looking for the surefire way to disconnect that works in all situations, including when the socket is broken. – johnnycrash Sep 26 '17 at 02:00
  • What happens when the other end is misbehaving or unreachable and doesn't respond to ShutDown()? – johnnycrash Sep 26 '17 at 02:02
  • You can timeout the socket if you need to. Just be aware that there may be a delay in being able to re-establish the connection when you do this. Of course, if the other endpoint is in fact unreachable, a delay doesn't matter because you won't be able to reconnect anyway. – Peter Duniho Sep 26 '17 at 02:59