【问题标题】:Why does .Net Socket.Disconnect take two minutes?为什么 .Net Socket.Disconnect 需要两分钟?
【发布时间】:2019-02-21 22:04:54
【问题描述】:

我正在使用 .Net 的套接字类,我正在使用以下代码:

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

这会阻塞整整两分钟。我指定了 true,因为我将立即重用套接字并重新建立连接。无论我在那里有关闭电话,它都会阻塞两分钟。我唯一能做的就是通过 false 断开连接。但是我想重用socket。

有什么想法吗?

更新:

我已阅读代码。我已经设置了 DontLinger 选项。它没有帮助。

更新 2:

我已根据请求添加了网络跟踪:

跟踪 1:使用 DontLinger 选项

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:使用关机(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() 

【问题讨论】:

  • 我们能看到一些周围的代码吗?可能是其他原因导致延迟,例如循环或阻塞调用。

标签: .net sockets


【解决方案1】:

如果另一端 Socket 未接收,则会发生 Shutdown 和 Disconnect 或 BeginDisconnect 的超时。

这里是如何工作的: Shutdown(SocketShutdown.Send)(或两者)向另一端产生零字节的 SENDING。 然后,如果您调用 Disconnect,它将阻塞,直到对方接受这个零字节数据包。 这就是为什么套接字在从 Socket 优雅断开期间接受期间总是接收零字节的原因。 延迟选项和其他设置对这 2 分钟的延迟没有影响。您可以使用 TCPView 检查连接状态。 因此,正确的方法是确保另一端处于接收模式或物理断开连接或实际破坏套接字 - 例如应用程序退出(在这种情况下,您将立即获得异常,无需 2 分钟延迟)。

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

【讨论】:

    【解决方案2】:

    这可能就是你要找的。​​p>

    如果您需要在没有先调用 Shutdown 的情况下调用 Disconnect,您可以将 DontLinger Socket 选项设置为 false 并指定一个非零超时间隔,以确保发送排队等待传出传输的数据。断开连接然后阻塞,直到发送数据或直到指定的超时到期。如果您将 DontLinger 设置为 false 并指定零超时间隔,则 Close 会释放连接并自动丢弃传出的排队数据。

    来自docs

    【讨论】:

    • 我已经读过了。这没用。即使这部分说没有。好吧,我确实调用了关机,所以所有这些都是无效的。
    • 据我所知,如果使用关闭它会导致“在套接字关闭之前发送和接收所有数据”[Docs]。这导致了2分钟的延迟,因为它在关闭之前完成了数据的发送和接收。延迟可能更长或更短,具体取决于发送/接收的数据。
    • 所以它只是选择延迟 2 分钟以确保发送/接收数据。听起来很可怕。
    • 我刚试过没有关机,我已经将套接字选项DontLinger设置为true,它仍然阻塞2分钟。
    【解决方案3】:

    这可能与Linger 选项有关。更多信息请看这里:Graceful Shutdown, Linger Options, and Socket Closure

    在 .NET 中,您可以使用 Socket.SetSocketOption 方法对其进行更改。

    编辑:如果不是 Linger 选项,您应该尝试启用完整的套接字跟踪,这是一个 .config 示例:

    <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>
    

    编辑:或者您可以点击所谓的 TIME_WAIT,此处描述为:Please explain the TIME_WAIT state,即 120 毫秒。通常最好将 Close() 与 SocketOptionName.ReuseAddress 一起使用,而不是使用 Disconnect(true)。参见 cmets here 以及(在 cmets 部分)。

    【讨论】:

    • 我已经尝试设置 DontLinger 选项。这没用。无论如何,我使用了 Socket.ShutDown 所以它不应该是必要的。
    • 我已经尝试过打开和关闭不要逗留并获得相同的跟踪。我已经用跟踪更新了我的问题。
    • 使用 Shutdown both 方法添加了第二个跟踪。
    • 你应该使用 SetSocketOption ReuseAddress + Close 而不是 Disconnect(true) (我已经更新了我的答案)
    • @Simon:我从 Win Sock 2 API 看到了这一点。我以为它提到了这个注册表项参数 TcpTimedWaitDelay。我去设置它,它没有任何区别。让我试试你的其他建议。谢谢:)
    【解决方案4】:

    这需要 2 分钟,因为服务器可能在收到客户端关闭调用的 0 字节时没有关闭套接字。

    所以客户端调用关机。服务器收到 0 个字节。 客户端调用 Disconnect :disconnect 将等待来自服务器端的套接字关闭。 如果服务器不关闭套接字,客户端断开连接将需要 2 分钟(超时)。 如果服务器关闭套接字,则几乎立即断开连接。

    【讨论】:

      【解决方案5】:

      原来有一些注册表项可以控制断开连接需要多长时间。它与 WinSock2 api 有关。

      【讨论】:

      • 也有同样的问题,解决方法是什么?
      猜你喜欢
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      • 2015-11-07
      相关资源
      最近更新 更多