Eugene D. Gubenkov
Eugene D. Gubenkov

Reputation: 5357

ASP.NET WebMethod and half-open connections

Consider the situation where some client calls WebMethod and after connection was established the host process crashes and connection becomes half-open. Will ASP.NET WebMethod proxy automatically detect it?

We assume that WebMethod timeout settled to the infinity or some big amount of time. Will connectivity error be detected only on TCP keep-alive packet sending (after 2 hours of idle on Windows by default)?

[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 Reference proxy call:

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();
}

UPDATE.

I've tried multiple scenarios and here the results that I got using Wireshark to see what is going on under the hood.

  1. Stopping hosting Web Server (IIS) through the IIS Manager or killing host process (w3wp.exe): enter image description here

In both cases client notified via sending TCP RST flag. Seems Windows takes care of closing sockets for crashed/killed processes. In .NET the System.Net.WebException will be thrown:

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. Killed the host process after connectivity (to the host) loss, so TCP RST can not reach client: Results here is very tangling for me, because after 2.5 hours the broken connection (half-open) is not detected and client still thinks that underlying TCP connection is alive (the same situation after 6 hours). Here the output from Sysinternals TCPView:
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 output:

after 2.5 hours of half-open connection

I've checked KeepAliveTime registry setting on my system here:

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
and it was missing, so the default 2 hours should be used (?).

Can anybody explain the result described in the second point? Why TCP keepalive was not sent? Is proxy explicitly settled up different keepalive behavior for underlying socket (https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx)?

Upvotes: 4

Views: 1257

Answers (2)

ohmusama
ohmusama

Reputation: 4215

It looks like the keep alive is not garanteed because things might muck with that setting in windows (no the registry value isn't the end all).

According to this: Windows TCP socket has SO_KEEPALIVE enabled by default?

It looks like you should not rely on this behavior and set a timeout. If you are using a soap request, you could always invoke an async request, and then wait on the request based on a client configurable value, and have a nice logic handling for timeouts.

Upvotes: 2

slvnperron
slvnperron

Reputation: 1343

If the host process crashes the connection will close. It won't wait for the TCP keep-alive to kick. You can easily test this scenario by spinning your WebService and making it crash voluntary.

Upvotes: 2

Related Questions