Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does .Net Socket.Disconnect take two minutes?

Tags:

.net

sockets

I am using .Net's socket class and I am using the following code:

socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(true);

This then blocks for exactly two minutes. I have specified true because I am going to reuse the socket immediately and re-establish the connection. Whether I have the Shutdown call in there or not it blocks for two minutes. The only thing I can do is pass false to disconnect. But I want to reuse the socket.

Any ideas?

UPDATE:

I have read the codes. I have set the DontLinger option. It does not help.

UPDATE 2:

I have added a network trace as per request:

Trace 1: Using the DontLinger option

System.Net.Sockets Verbose: 0 : [4668] Socket#5009246::Socket(InterNetwork#2)
System.Net.Sockets Verbose: 0 : [4668] Exiting Socket#5009246::Socket() 
System.Net.Sockets Verbose: 0 : [4668] Socket#5009246::Connect(eee:nnnn#-2063562120)
System.Net.Sockets Information: 0 : [4668] Socket#5009246 - Created connection from aaa.bbb.ccc.ddd.eee:nnnnn to www.xxx.yyy.zzz.:mmmm.
System.Net.Sockets Verbose: 0 : [4668] Exiting Socket#5009246::Connect() 
System.Net.Sockets Verbose: 0 : [4668] Socket#5009246::Disconnect()
System.Net.Sockets Verbose: 0 : [4668] Exiting Socket#5009246::Disconnect() 

Trace 2: Using the Shutdown(SocketShutdown.Both);

System.Net.Sockets Verbose: 0 : [0300] Socket#5009246::Socket(InterNetwork#2)
System.Net.Sockets Verbose: 0 : [0300] Exiting Socket#5009246::Socket() 
System.Net.Sockets Verbose: 0 : [0300] Socket#5009246::Connect(ddd:eeeee#-2063562120)
System.Net.Sockets Information: 0 : [0300] Socket#5009246 - Created connection from aaa.bbb.ccc.ddd:eeee to www.xxx.yyyy.zzzz:nnnnn.
System.Net.Sockets Verbose: 0 : [0300] Exiting Socket#5009246::Connect() 
System.Net.Sockets Verbose: 0 : [0300] Socket#5009246::Shutdown(Both#2)
System.Net.Sockets Verbose: 0 : [0300] Exiting Socket#5009246::Shutdown() 
System.Net.Sockets Verbose: 0 : [0300] Socket#5009246::Disconnect()
System.Net.Sockets Verbose: 0 : [0300] Exiting Socket#5009246::Disconnect() 
like image 775
uriDium Avatar asked Dec 03 '10 13:12

uriDium


3 Answers

Timeout in case of Shutdown followed by Disconnect or BeginDisconnect will occur in the case if the other side Socket is not Receiving.

Here how it works: Shutdown(SocketShutdown.Send) (or Both) produce SENDING of zero byte to other side. And then if you call Disconnect it will block until other side accept this zero byte packet. This is why socket always receive zero byte during in Accept during graceful disconnection from Socket. Linger option and other settings have no effect on this 2 minute delay. You may check connection state with TCPView. So proper way is to make sure other side is either in Receive mode OR physically disconnected OR actually destroyed socket - for example application quit (you will get immediate exception in this case without 2 minute delay).

http://vadmyst.blogspot.ru/2008/04/proper-way-to-close-tcp-socket.html

like image 189
Konstantin Salavatov Avatar answered Nov 08 '22 19:11

Konstantin Salavatov


This might be what you are looking for.

If you need to call Disconnect without first calling Shutdown, you can set the DontLinger Socket option to false and specify a nonzero time-out interval to ensure that data queued for outgoing transmission is sent. Disconnect then blocks until the data is sent or until the specified time-out expires. If you set DontLinger to false and specify a zero time-out interval, Close releases the connection and automatically discards outgoing queued data.

From the docs.

like image 21
Tony Abrams Avatar answered Nov 08 '22 17:11

Tony Abrams


That may be to the Linger option. See here for more information: Graceful Shutdown, Linger Options, and Socket Closure

in .NET, you can change it with the Socket.SetSocketOption method.

EDIT: if it's not the Linger option, you should try to enable full socket traces, here is a .config sample:

<configuration>
  <system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.Net.Sockets">
        <listeners>
          <add name="SocketsTrace"/>
        </listeners>
      </source>
    </sources>

    <sharedListeners>
      <add name="SocketsTrace" type="System.Diagnostics.TextWriterTraceListener" initializeData="SocketsTrace.log" />
    </sharedListeners>

    <switches>
      <add name="System.Net.Sockets" value="Verbose" />
    </switches>
 </configuration>

EDIT: or you can hit what's called the TIME_WAIT, described here: Please explain the TIME_WAIT state which is 120ms. It's generally better to use Close() with the SocketOptionName.ReuseAddress rather than to use Disconnect(true). See comments here as well (in the comments section).

like image 1
Simon Mourier Avatar answered Nov 08 '22 18:11

Simon Mourier