How to determine if the tcp is connected or not?

2019-03-09 22:48发布

I have tcpclient object and i want to determine if it's connected or not. i use connected property of tcpclient but it returns the state of last operation. so its not useful.

then i use this code :

bool flag;
flag = (tcp.Client.Poll(10000, SelectMode.SelectWrite));

and

 if( tcp.Client.Poll( 0, SelectMode.SelectRead ) )
 {
   byte[] buff = new byte[1];
   if( tcp.Client.Receive( buff, SocketFlags.Peek ) == 0 )
   {
     flag = false;
   }
 }

but it does not work properly.

Any idea?


this is my code in server side :

   private ArrayList _ClientList = new ArrayList();

   public ClsServer(int port)
    {
        _TCPListener = new TcpListener(IPAddress.Any, port);
        _TCPListener.Start();

        Thread ListenThread = new Thread(new ThreadStart(ListenForClients));
        ListenThread.IsBackground = true;
        ListenThread.Start();
    }

    private void ListenForClients()
    {            
        while (true)
        {
            //blocks until a client has connected to the server
            TcpClient client = this._TCPListener.AcceptTcpClient();
            client.ReceiveTimeout = 0;

            //create a thread to handle communication with connected client
            Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
            clientThread.IsBackground = true;
            clientThread.Start(client);
        }
    }

    private void HandleClientComm(object client)
    {
        try
        {
            TcpClient tcpClient = (TcpClient)client;               
            AddObject(tcpclient);

            int bytesRead;
            string message = "";
            byte[] RecievedPack = new byte[1024 * 1000];

            NetworkStream clientStream = tcpClient.GetStream();
            while (true)
            {
                bytesRead = 0;
                try
                {
                    ////blocks until a client sends a message
                    bytesRead = clientStream.Read(RecievedPack, 0, RecievedPack.Length);
                    int Len = BitConverter.ToInt32(RecievedPack, 0);
                    message = UTF8Encoding.UTF8.GetString(RecievedPack, 0, Len);
                }
                catch (Exception er)
                {
                    //When Client is disconnected
                    if (er.GetType() == typeof(IOException))
                    {
                        RemoveObject(client);
                        break;
                    }
                }                   
                //message has successfully been received                          
               // do something
            }

            RemoveObject(client);
        }
        catch(Exception e)
        {
           // RemoveObject(client);
        }
    }

    private void AddObject(object obj)
    {            
        int totalcount, index;
        totalcount = _ClientList.Count;
        index = 0;
        while (index < totalcount)
        {
            TcpClient alcobj = (TcpClient)_ClientList[index];
            try
            {
                if (IPAddress.Equals(((IPEndPoint)alcobj.Client.RemoteEndPoint).Address,
                   ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address))
                {
                    _ClientList.Remove(alcobj);
                    break;
                }
                index++;
            }
            catch (Exception er)
            {
                if (er.GetType() == typeof(ObjectDisposedException))
                    RemoveObject(alcobj);
            }
            finally
            {
                totalcount = _ClientList.Count;
            }
        }            
         _ClientList.Add(obj);             
    }

    private void RemoveObject(object obj)
    {            
        if (_ClientList.IndexOf(obj) > -1)
        {
            _ClientList.Remove(obj);
            SendClientState(IP, false);
        }         
    }

and this is the client side :

    public bool IsConnected
    {           
            try
            {
                if (_TcpClient != null && _TcpClient.Client != null && _TcpClient.Client.Connected)
                {
                    // Detect if client disconnected
                    if (_TcpClient.Client.Poll(0, SelectMode.SelectRead))
                    {
                        byte[] buff = new byte[1];
                        if (_TcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
                        {
                            // Client disconnected
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }

                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
    }

   private void clsClient()
   {
          if(!IsConnected()) 
          {
                  Connecttoserver()
           }
    }

    private void ConnectToServer()
    {
        try
        {
            NetworkStream _NetworkStream = _TcpClient.GetStream();
            byte[] _RecievedPack = new byte[1024 * 1000];
            string _Message = string.Empty;
            int _BytesRead;
            int _Length;

            while (true)
            {
                _BytesRead = _NetworkStream.Read(_RecievedPack, 0, _RecievedPack.Length);
                _Length = BitConverter.ToInt32(_RecievedPack, 0);
                _Message = UTF8Encoding.UTF8.GetString(_RecievedPack, 4, _Length);

                if (_BytesRead != 0)
                {
                    if (OnReceive != null)
                        // do something

                    _NetworkStream.Flush();
                }
            }
        }
        catch (Exception exp)
        {
            // do something 
        }
    }

in client side, IsConnected() always return false and try to connecttoserver, so the server listener always try to add the client in a list

4条回答
Viruses.
2楼-- · 2019-03-09 23:06

I agree with Lior Ohana because I had this problem with remote devices that were used GPRS Tcp connection. when device is turn off or disconnected, it did not alert to the sever. There for I used this code: I send Specific time to the clients

void AnalyzeForHandShaking(Socket socketin, string Message)

    {
        Socket handler = socketin;

        try
        {
            Message = Message.Trim();

            if (!string.IsNullOrEmpty(Message.Trim()))

               // if (Message.Equals("~"))
                {

                   // string Serial = getSerialFromSocket(socketin).Trim();
                    DateTime dt = DateTime.Now; 

                    if (handler!=null)
                    //if there is serial in hastable
                    if (!arrIPTimeHandShaking.ContainsKey(handler))
                    {
                        arrIPTimeHandShaking.Add(handler, dt);
                    }
                    else
                    {
                        arrIPTimeHandShaking[handler] = dt;
                    }
                }
        }
        catch
        {

        }
    }
查看更多
ら.Afraid
3楼-- · 2019-03-09 23:07

I suggest not relaying on such methods. For my opinion, the best way is to implement some kind of keep-alive mechanism. Every X seconds, send a small message and wait for an answer. You're probably disconnected when: 1. You catch an exception when trying to send a keep-alive message (if you're the client side). 2. You don't get a keep-alive message/response for some period of time.

I also suggest not to count on the built-in TCP keep-alive, I found it very not-reliable.

Updated: Found a nice post for this matter: Post

查看更多
\"骚年 ilove
4楼-- · 2019-03-09 23:17

Use this code instead, I have tested it and using it in real production software:

public bool IsConnected
{
    get
    {
        try
        {
            if (_tcpClient != null && _tcpClient.Client != null && _tcpClient.Client.Connected)
            {
               /* pear to the documentation on Poll:
                * When passing SelectMode.SelectRead as a parameter to the Poll method it will return 
                * -either- true if Socket.Listen(Int32) has been called and a connection is pending;
                * -or- true if data is available for reading; 
                * -or- true if the connection has been closed, reset, or terminated; 
                * otherwise, returns false
                */

                // Detect if client disconnected
                if (_tcpClient.Client.Poll(0, SelectMode.SelectRead))
                {
                    byte[] buff = new byte[1];
                    if (_tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
                    {
                        // Client disconnected
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }

                return true;
            }
            else
            {
                return false;
            }
        }
        catch
        {
            return false;
        }
    }
}

Edit: However you can't rely on just checking the connection and if true proceed, because it returning the status of connection at time this property executed, for instance after you check IsConnected and it returns true, and while you are in the middle of communication, the connection maybe lost there! we just use it in the first place to reduce the probability of failure, So you have to wrap the whole communication in a try/catch and expect the connection to be lost at any time!

查看更多
欢心
5楼-- · 2019-03-09 23:17

The only way to know whether or not the other end of a socket connection is still connected is by catching the result of a read or write operation or possibly catching an exception.

For more information please refer to this StackOverflow question: Instantly detect client disconnection from server socket

Here is a small snippet of code that is simply using a Socket in non-blocking mode and connected to a server.

                try
                {
                    bytesRead = nambSok.Receive(message, 4096, SocketFlags.None);
                }
                catch (SocketException e)
                {
                    //a socket error has occured
                    switch (e.SocketErrorCode)
                    {
                        case System.Net.Sockets.SocketError.TimedOut:
                        case System.Net.Sockets.SocketError.WouldBlock:
                            if (doDisconnect == false)
                            {
                                continue;
                            }
                            break;

                        case System.Net.Sockets.SocketError.ConnectionReset:
                        case System.Net.Sockets.SocketError.ConnectionAborted:
                            isConnected = false;
                            break;
                    }
                }

                if (bytesRead > 0)
                {
                    /* do something with data */
                }

The "keep-alive" method Lior Ohana proposed is also a great idea. Force each client to "check in" every X seconds. The client can detect the server is gone if an exception occurs on the write, and the server knows the client has gone away if a "keep-alive" message hasn't been received in X seconds.

查看更多
登录 后发表回答