How to test for a broken connection of TCPClient after being connected?

前端 未结 6 1544
-上瘾入骨i
-上瘾入骨i 2020-12-14 03:08

I\'ve been fighting with one problem for a whole 3 days I can\'t find any solution, please help :)
I work with Visual Studio 2010 and C# language.

I have a devic

相关标签:
6条回答
  • 2020-12-14 03:49

    Simple answer. You can't. Tcp is made in a way which doesn't allow this. However, the normal way to achieve this is to send ping's with shorter interval than messages. So, say, that whenever you get a message from the server, you start a clock that count down 1 min, then you send a "ping" command (if you haven't received a new message in between). If you don't receive a response to your "ping" within 30 seconds, you conclude that the connection is broken.

    Theoretically, you should be able to do this on a package-level (tcp sends ACK which you should be able to check for), but I don't know if that's possible in C#, or any programming language for that matter, or if you need to do that in firmware/hardware.

    0 讨论(0)
  • 2020-12-14 03:52

    Just in case anyone else needs something simple and effective.

    This is the code I came up with

                while (true)
                {
    
                    string s = null;
                    DateTime readLag = DateTime.Now;
                    try
                    {
                        s = streamIn.ReadLine();
                    }
                    catch (Exception ex)
                    {
                        SocketException sockEx = ex.InnerException as SocketException;
                        if (sockEx != null)
                        {
                            OnDebug("(" + sockEx.NativeErrorCode + ") Exception = " + ex);
                        }
                        else
                        {
                            OnDebug("Not SockEx :" + ex);
                        }
                    }
    
    
    
                    if (enableLog) OnDebug(s);
                    if (s == null || s == "")
                    {
                        if (readLag.AddSeconds(.9) > DateTime.Now)
                        {
                            break;
                        }
                    }
                    else
                    {
                        CommandParser(s);
                    }
                }
    

    What I got was native error 10035 every time a read failed but would block.

    When the connection was trashed, I instantly got a return with no data.

    Setting the readLag.AddSeconds() to just below my read timeout would give me a pretty good idea that the time never elapsed, and I got no data. Which should not happen.

    Soon as this criteria popped up, I just kick out of the loop and the thread ends.

    Hope this helps anyone else out there.

    0 讨论(0)
  • 2020-12-14 03:53

    There is a socket option called SO_KEEPALIVE from the oginal unix implemetnation that has the TCP protocol send occasional probes to make sure the other end of the pipe is still listening. It can be set along with how often the probes are set via Socket.IOControl

    0 讨论(0)
  • 2020-12-14 03:58

    I think this is a question that often comes around. This might be why MSDN docs really give a good answer to this - see Socket.Connected

    Quote from there:

    The Connected property gets the connection state of the Socket as of the last I/O operation. When it returns false, the Socket was either never connected, or is no longer connected.

    The value of the Connected property reflects the state of the connection as of the most recent operation. If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.

    with this sample code:

    // .Connect throws an exception if unsuccessful
    client.Connect(anEndPoint);
    
    // This is how you can determine whether a socket is still connected.
    bool blockingState = client.Blocking;
    try
    {
        byte [] tmp = new byte[1];
    
        client.Blocking = false;
        client.Send(tmp, 0, 0);
        Console.WriteLine("Connected!");
    }
    catch (SocketException e) 
    {
        // 10035 == WSAEWOULDBLOCK
        if (e.NativeErrorCode.Equals(10035))
            Console.WriteLine("Still Connected, but the Send would block");
        else
        {
            Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
        }
    }
    finally
    {
        client.Blocking = blockingState;
    }
    
     Console.WriteLine("Connected: {0}", client.Connected);
    

    and the straight forward motification for an extension-method:

    public static bool IsConnected(this Socket client)
    {
       // This is how you can determine whether a socket is still connected.
       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-12-14 04:12

    This is a very old thread, but it's the first SO post that came up when I searched for this question and I found a more useful solution somewhere else, so I thought I'd post a link to it to help others in the future:

    https://social.msdn.microsoft.com/Forums/en-US/c857cad5-2eb6-4b6c-b0b5-7f4ce320c5cd/c-how-to-determine-if-a-tcpclient-has-been-disconnected?forum=netfxnetcom&prof=required

    ElFenix posted this answer that worked for me:

    // Detect if client disconnected
    if (tcp.Client.Poll(0, SelectMode.SelectRead))
    {
      byte[] buff = new byte[1];
      if (tcp.Client.Receive(buff, SocketFlags.Peek) == 0)
      {
        // Client disconnected
        bClosed = true;
      }
    }
    
    0 讨论(0)
  • 2020-12-14 04:12

    it will be correct and working if you type the following:

    byte[] tmp = new byte[] {0};
    ...             
    client.Send(tmp, 1, 0);
    ...
    
    0 讨论(0)
提交回复
热议问题