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

前端 未结 11 1162
礼貌的吻别
礼貌的吻别 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:00

    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.

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

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

    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

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

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

    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
    
    0 讨论(0)
提交回复
热议问题