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

前端 未结 11 1163
礼貌的吻别
礼貌的吻别 2020-11-28 18:50

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 discon

相关标签:
11条回答
  • 2020-11-28 19:13

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 19:17

    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.

    0 讨论(0)
  • 2020-11-28 19:25

    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.

    0 讨论(0)
  • 2020-11-28 19:25

    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.

    0 讨论(0)
  • 2020-11-28 19:25

    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!

    0 讨论(0)
提交回复
热议问题