How to check if a socket is connected/disconnected in C#?

C#SocketsConnection

C# Problem Overview


How can you check if a network socket (System.Net.Sockets.Socket) is still connected if the other host doesn't send you a packet when it disconnects (e.g. because it disconnected ungracefully)?

C# Solutions


Solution 1 - C#

As Paul Turner answered Socket.Connected cannot be used in this situation. You need to poll connection every time to see if connection is still active. This is code I used:

bool SocketConnected(Socket s)
{
    bool part1 = s.Poll(1000, SelectMode.SelectRead);
    bool part2 = (s.Available == 0);
    if (part1 && part2)
        return false;
    else
        return true;
}

It works like this:

  • s.Poll returns true if
    • connection is closed, reset, terminated or pending (meaning no active connection)
    • connection is active and there is data available for reading
  • s.Available returns number of bytes available for reading
  • if both are true:
    • there is no data available to read so connection is not active

Solution 2 - C#

As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into consideration that the socket might not have been initialized in the first place. This is the last (I believe) piece of information and it is supplied by the Socket.Connected property. The revised version of the method would looks something like this:

 static bool IsSocketConnected(Socket s)
    {
        return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);

/* The long, but simpler-to-understand version:

        bool part1 = s.Poll(1000, SelectMode.SelectRead);
        bool part2 = (s.Available == 0);
        if ((part1 && part2 ) || !s.Connected)
            return false;
        else
            return true;
        
*/
    }

Solution 3 - C#

The Socket.Connected property will tell you whether a socket thinks it's connected. It actually reflects the status of the last send/receive operation performed on the socket.

If the socket has been closed by your own actions (disposing the socket, calling methods to disconnect), Socket.Connected will return false. If the socket has been disconnected by other means, the property will return true until you next attempt to send or recieve information, at which point either a SocketException or ObjectDisposedException will be thrown.

You can check the property after the exception has occurred, but it's not reliable before.

Solution 4 - C#

The accepted answer doesn't seem to work if you unplug the network cable. Or the server crashes. Or your router crashes. Or if you forget to pay your internet bill. Set the TCP keep-alive options for better reliability.

public static class SocketExtensions
{
    public static void SetSocketKeepAliveValues(this Socket instance, int KeepAliveTime, int KeepAliveInterval)
    {
        //KeepAliveTime: default value is 2hr
        //KeepAliveInterval: default value is 1s and Detect 5 times

        //the native structure
        //struct tcp_keepalive {
        //ULONG onoff;
        //ULONG keepalivetime;
        //ULONG keepaliveinterval;
        //};

        int size = Marshal.SizeOf(new uint());
        byte[] inOptionValues = new byte[size * 3]; // 4 * 3 = 12
        bool OnOff = true;

        BitConverter.GetBytes((uint)(OnOff ? 1 : 0)).CopyTo(inOptionValues, 0);
        BitConverter.GetBytes((uint)KeepAliveTime).CopyTo(inOptionValues, size);
        BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo(inOptionValues, size * 2);

        instance.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
    }
}



// ...
Socket sock;
sock.SetSocketKeepAliveValues(2000, 1000);

The time value sets the timeout since data was last sent. Then it attempts to send and receive a keep-alive packet. If it fails it retries 10 times (number hardcoded since Vista AFAIK) in the interval specified before deciding the connection is dead.

So the above values would result in 2+10*1 = 12 second detection. After that any read / wrtie / poll operations should fail on the socket.

Solution 5 - C#

public static class SocketExtensions
{
    private const int BytesPerLong = 4; // 32 / 8
    private const int BitsPerByte = 8;

    public static bool IsConnected(this Socket socket)
    {
        try
        {
            return !(socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0);
        }
        catch (SocketException)
        {
            return false;
        }
    }


    /// <summary>
    /// Sets the keep-alive interval for the socket.
    /// </summary>
    /// <param name="socket">The socket.</param>
    /// <param name="time">Time between two keep alive "pings".</param>
    /// <param name="interval">Time between two keep alive "pings" when first one fails.</param>
    /// <returns>If the keep alive infos were succefully modified.</returns>
    public static bool SetKeepAlive(this Socket socket, ulong time, ulong interval)
    {
        try
        {
            // Array to hold input values.
            var input = new[]
            {
                (time == 0 || interval == 0) ? 0UL : 1UL, // on or off
				time,
                interval
            };

            // Pack input into byte struct.
            byte[] inValue = new byte[3 * BytesPerLong];
            for (int i = 0; i < input.Length; i++)
            {
                inValue[i * BytesPerLong + 3] = (byte)(input[i] >> ((BytesPerLong - 1) * BitsPerByte) & 0xff);
                inValue[i * BytesPerLong + 2] = (byte)(input[i] >> ((BytesPerLong - 2) * BitsPerByte) & 0xff);
                inValue[i * BytesPerLong + 1] = (byte)(input[i] >> ((BytesPerLong - 3) * BitsPerByte) & 0xff);
                inValue[i * BytesPerLong + 0] = (byte)(input[i] >> ((BytesPerLong - 4) * BitsPerByte) & 0xff);
            }

            // Create bytestruct for result (bytes pending on server socket).
            byte[] outValue = BitConverter.GetBytes(0);

            // Write SIO_VALS to Socket IOControl.
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            socket.IOControl(IOControlCode.KeepAliveValues, inValue, outValue);
        }
        catch (SocketException)
        {
            return false;
        }

        return true;
    }
}
  1. Copy the SocketExtensions class to your project
  2. Call the SetKeepAlive on your socket - socket.SetKeepAlive(1000, 2);
  3. Add a timer to check the IsConnected function

Solution 6 - C#

I made an extension method based on this MSDN article. This is how you can determine whether a socket is still connected.

public static bool IsConnected(this Socket client)
{
    bool blockingState = client.Blocking;

    try
    {
        byte[] tmp = new byte[1];

        client.Blocking = false;
        client.Send(tmp, 0, 0);
        return true;
    }
    catch (SocketException e)
    {
        // 10035 == WSAEWOULDBLOCK
        if (e.NativeErrorCode.Equals(10035))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    finally
    {
        client.Blocking = blockingState;
    }
}

Solution 7 - C#

As Alexander Logger pointed out in zendars answer, you have to send something to be completely sure. In case your connected partner does not read on this socket at all, you can use the following code.

bool SocketConnected(Socket s)
{
  // Exit if socket is null
  if (s == null)
    return false;
  bool part1 = s.Poll(1000, SelectMode.SelectRead);
  bool part2 = (s.Available == 0);
  if (part1 && part2)
    return false;
  else
  {
    try
    {
      int sentBytesCount = s.Send(new byte[1], 1, 0);
      return sentBytesCount == 1;
    }
    catch
    {
      return false;
    }
  }
}

But even then it might take a few seconds until a broken network cable or something similar is detected.

Solution 8 - C#

The best way is simply to have your client send a PING every X seconds, and for the server to assume it is disconnected after not having received one for a while.

I encountered the same issue as you when using sockets, and this was the only way I could do it. The socket.connected property was never correct.

In the end though, I switched to using WCF because it was far more reliable than sockets.

Solution 9 - C#

Following the advice from NibblyPig and zendar, I came up with the code below, which works on every test I made. I ended up needing both the ping, and the poll. The ping will let me know if the cable has been disconnected, or the physical layer otherwise disrupted (router powered off, etc). But sometimes after reconnect I get a RST, the ping is ok, but the tcp state is not.

#region CHECKS THE SOCKET'S HEALTH
	if (_tcpClient.Client.Connected)
	{
			//Do a ping test to see if the server is reachable
			try
			{
				Ping pingTest = new Ping()
				PingReply reply = pingTest.Send(ServeripAddress);
				if (reply.Status != IPStatus.Success) ConnectionState = false;
			} catch (PingException) { ConnectionState = false; }

			//See if the tcp state is ok
			if (_tcpClient.Client.Poll(5000, SelectMode.SelectRead) && (_tcpClient.Client.Available == 0))
			{
				ConnectionState = false;
			}
		}
	}
	else { ConnectionState = false; }
#endregion

Solution 10 - C#

Just use the KeepAlive like @toster-cx says and then use the Socket Connected status to check if the Socket is still connected. Set your receive timeout at the same timeout of the keepalive. If you have more questions i am always happy to help!

Solution 11 - C#

Use Socket.Connected Property.

--UPDATE--

As Paul Turner answered Socket.Connected cannot be used in this situation. You need to poll connection every time to see if connection is still active. See 2

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlesderidView Question on Stackoverflow
Solution 1 - C#zendarView Answer on Stackoverflow
Solution 2 - C#AutomaticoView Answer on Stackoverflow
Solution 3 - C#Paul TurnerView Answer on Stackoverflow
Solution 4 - C#toster-cxView Answer on Stackoverflow
Solution 5 - C#Amir TouitouView Answer on Stackoverflow
Solution 6 - C#Kim Ki WonView Answer on Stackoverflow
Solution 7 - C#Johannes RabauerView Answer on Stackoverflow
Solution 8 - C#NibblyPigView Answer on Stackoverflow
Solution 9 - C#M GranjaView Answer on Stackoverflow
Solution 10 - C#Condra963View Answer on Stackoverflow
Solution 11 - C#KMånView Answer on Stackoverflow