Socket.Close doesn't really close tcp socket? (c#)

18,766

Solution 1

It will close the .NET part of the socket. However according to the TCP specification the OS have to keep the lower level tidbits of the socket open for a certain amount of time in order to detect retransmission, and similar. In this particular case it's likely keeping the socket around for a bit in order to detect a reply to the SYN packet sent so it can reply more sensibly and not mix up the reply with further packets sent.

Solution 2

By design, you should always call Shutdown before closing the socket.

mySocket.Shutdown(SocketShutdown.Both);
mySocket.Close();

Doing so effectively disables send and receive on the socket, so it will not be accepting incoming data after you've closed it, even if the OS still has control of it.

Jon Skeet also has a point, that since you're opening the connection asynchronously, it may actually be connecting while you're trying to close it. However, if you call Shutdown on it, it will not allow information to be received as you are experiencing.

Edit: You can only Shutdown a socket that is already connected, so bear this in mind as you write your code.

Solution 3

You're calling *Begin*Connect - so doing it asynchronously. You're quite possibly trying to close the socket before it's even connected - so when it then connects, it remains open.

Try connecting synchronously - or closing it in OnSocketConnected so you can see the effect of closing a genuinely connected socket.

Share:
18,766
r0u1i
Author by

r0u1i

Updated on June 05, 2022

Comments

  • r0u1i
    r0u1i about 2 years

    It seems that using socket.Close() for a tcp socket, doesn't fully close the socket. In the following example I'm trying to connect to example.com at port 9999, which is not opened, and after a short-timeout, I'm trying to close the socket.

      for (int i = 0; i < 200; i++)
      {
        Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        sock.LingerState = new LingerOption(false, 0);
        sock.BeginConnect("www.example.com", 9999, OnSocketConnected, sock);
        System.Threading.Thread.Sleep(50);
        sock.Close();
      }
    

    But when I take a look at netstat after the loop completes, I find that there are many half-opened sockets:

      TCP    israel-xp:6506         www.example.com:9999   SYN_SENT
      TCP    israel-xp:6507         www.example.com:9999   SYN_SENT
      TCP    israel-xp:6508         www.example.com:9999   SYN_SENT
      TCP    israel-xp:6509         www.example.com:9999   SYN_SENT
    

    EDIT . Ok, some context was missing. I'm using beginconnect because I expect the socket connection to fail (9999 is not opened), and in my real code, I call the socket.Close() once a timer is set. On OnSocketConnected I call EndConnect, which throws an exception (trying to call a method of a disposed object). My goal is having a short timeout for the socket connection stage.

    Any clue what I'm doing wrong? Thanks!

  • r0u1i
    r0u1i over 14 years
    See my edit. I'm using BeginConnect on purpose, and my actual code waits for a timeout before calling Close. Just calling EndConnect on such a socket (where the dest port isn't opened), will just take a long time to complete. Or in other words, I want to timeout the socket connecting stage after X milliseconds (and not the absurdly high number of milliseconds windows has by default).
  • r0u1i
    r0u1i over 14 years
    ShutDown throws an excpetion if the socket is not yet connected - which is exactly my scenario.
  • r0u1i
    r0u1i over 14 years
    that makes sense, but isn't setting linger to false should solve it?
  • Ed Altorfer
    Ed Altorfer over 14 years
    Then you should use OnSocketConnected to call ShutDown on it and close it, or something of that nature.
  • Ed Altorfer
    Ed Altorfer over 14 years
    @Dean, this is the second question today for which Jon and I both posted replies at the same time. He already has too much reputation, maybe he can give me some. :)
  • r0u1i
    r0u1i over 14 years
    But calling ShutDown from OnSocketConnected misses the point of trying to timeout the connection process. Waiting for OnSocketConnected to be called, can take a long, long, time.
  • Ed Altorfer
    Ed Altorfer over 14 years
    But that's fine, because you don't care about the socket anymore. There is no way to completely just kill the socket if you try to connect it like you are. You need to either set a flag and then shut it down/close it, or not use asynchronous connections like that. Alternatively, you can just close it and be aware that SOME messages may be sent before the OS cleans up the socket.
  • r0u1i
    r0u1i over 14 years
    oh, linger doesn't do this. So, there isn't really a way to make Windows terminate the socket.
  • Jay
    Jay almost 14 years
    by default it will sit in the FIN_WAIT state for 4 minutes before Windows really closes it. Even more interesting is if you reopen the another connection to the same destination/port windows will reuse connections in FIN_WAIT that match.
  • supercat
    supercat over 13 years
    @Jay: The latter point can cause some considerable annoyance if dealing with TCP hardware that tends to pick the same destination port numbers every time it powers up and starts a new socket. If a connection is live when that happens, the device will figure the port number is no good and try a new port number. If the connection is in FIN_WAIT, however, it takes a long time for the device to figure something's not right.
  • binki
    binki about 6 years
    I think calling Socket.Dispose() is the only way to sort of be able to cancel an asynchronous connection with the current API. Seems like this would be done on purpose.