ASP.NET WebMethod和半开连接

时间:2015-02-04 21:12:38

标签: c# asp.net tcp

考虑一些客户端调用WebMethod的情况,并且在建立连接之后,主机进程崩溃并且连接变为半开。 ASP.NET WebMethod代理会自动检测它吗?

我们假设WebMethod超时已达到无限或大量时间。是否仅在TCP保持活动数据包发送时检测到连接错误(默认情况下在Windows上空闲2小时后)?

[WebService(Namespace = "http://www.example.com/TestService/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TestService : System.Web.Services.WebService
{
    [WebMethod]
    public void DoLongWork()
    {
        // long work here
    }
}

Web参考代理呼叫:

public void ServiceClient()
{
    var serviceProxy = new MyNamespace.TestService();
    // serviceProxy.Url = ...
    serviceProxy.Timeout = -1; // do not use timeout

    // will it wait for 2 hours (when TCP keep-alive will be sent) if connection was lost after handshake?
    serviceProxy.DoLongWork();
}

更新

我尝试过多个场景,这里是我使用Wireshark查看幕后内容的结果。

  1. 通过IIS管理器停止托管Web服务器(IIS)或终止主机进程(w3wp.exe): enter image description here
  2. 在这两种情况下,客户端通过发送TCP RST标志进行通知。似乎Windows负责关闭崩溃/被杀死进程的套接字。在.NET中,System.Net.WebException将被抛出:

    Unhandled Exception: System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
       at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
       at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
       --- End of inner exception stack trace ---
       at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
       at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
       at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)
       --- End of inner exception stack trace ---
       at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request)
       at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
       at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
       at WebMethodAndTCPHalfOpenTest.TestWebReference.TestService.DoLongWork(Int32 sec)
       at WebMethodAndTCPHalfOpenTest.Program.Main(String[] args) 
    1. 在连接(到主机)丢失后杀死主机进程,因此TCP RST无法访问客户端: 对于我来说这里的结果是非常纠结,因为在2.5小时后未检测到断开连接(半开)并且客户端仍然认为底层TCP连接存在(相同) 6小时后的情况)。这里是Sysinternals TCPView的输出:
    2. TCPView v3.01 - TCP/UDP endpoint viewer Copyright (C) 1998-2010
      Mark Russinovich and Bryce Cogswell Sysinternals -
      www.sysinternals.com
      
      [TCP] WebMethodAndTCPHalfOpenTest.exe
              PID:    8180
              State:  ESTABLISHED
              Local:  192.168.1.2
              Remote: 5.167.159.81
      Windows Version: Microsoft Windows [Version 6.1.7601]

      Wireshark输出:

      after 2.5 hours of half-open connection

      我已在我的系统上检查了KeepAliveTime注册表设置:

      HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
      但它已丢失,因此应使用默认的2小时(?)。

      第二点中描述的结果可以解释吗?为什么没有发送TCP keepalive?代理是否为底层套接字(https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx)显式确定了不同的keepalive行为?

2 个答案:

答案 0 :(得分:2)

如果主机进程崩溃,则连接将关闭。它不会等待TCP保持活跃。您可以通过旋转WebService并使其自动崩溃来轻松测试此方案。

答案 1 :(得分:2)

看起来保持活着并不保证,因为事情可能会破坏Windows中的设置(没有注册表值不是结束所有)。

根据这个: Windows TCP socket has SO_KEEPALIVE enabled by default?

看起来您不应该依赖此行为并设置超时。如果您正在使用soap请求,则可以始终调用异步请求,然后根据客户端可配置值等待请求,并对超时进行良好的逻辑处理。