it-swarm.com.de

Wie kann man feststellen, ob der TCP angeschlossen ist oder nicht?

Ich habe ein tcpclient-Objekt und möchte feststellen, ob es verbunden ist oder nicht. Ich verwende die Eigenschaft connected von tcpclient, aber sie gibt den Status der letzten Operation zurück. so ist es nicht nützlich.

dann benutze ich diesen Code:

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

und

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

aber es funktioniert nicht richtig.

Irgendeine Idee?


das ist mein Code auf der Serverseite:

   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);
        }         
    }

und das ist die Client-Seite:

    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 
        }
    }

auf der Clientseite gibt IsConnected () immer false zurück und versucht, connecttoserver zu verbinden, sodass der Server-Listener immer versucht, den Client einer Liste hinzuzufügen

14

Verwenden Sie stattdessen diesen Code. Ich habe ihn getestet und in echter Produktionssoftware verwendet:

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: Sie können sich jedoch nicht darauf verlassen, nur die Verbindung zu überprüfen, und wenn true, fahren Sie fort, weil der Status der Verbindung zum Zeitpunkt der Ausführung dieser Eigenschaft zurückgegeben wird. nachdem Sie beispielsweise IsConnected geprüft haben und true zurückgeben. und während Sie sich gerade in der Kommunikation befinden, könnte die Verbindung dort verloren sein! Wir verwenden es nur, um die Ausfallwahrscheinlichkeit zu reduzieren. Sie müssen also die gesamte Kommunikation in einen Try/Catch einwickeln und erwarten, dass die Verbindung jederzeit verloren geht!

20
Jalal Said

Ich schlage vor, auf solche Methoden nicht weiterzuverfolgen. Meiner Meinung nach ist es am besten, einen Keep-Alive-Mechanismus zu implementieren. Senden Sie alle X Sekunden eine kleine Nachricht und warten Sie auf eine Antwort. Sie sind wahrscheinlich getrennt, wenn: 1. Wenn Sie versuchen, eine Keep-Alive-Nachricht zu senden, fangen Sie eine Ausnahme ab (wenn Sie der Client sind). 2. Sie erhalten über einen bestimmten Zeitraum keine Keep-Alive-Nachricht/Antwort.

Ich schlage auch vor, nicht mit dem eingebauten TCP Keep-Alive zu rechnen, ich fand es sehr unzuverlässig.

Aktualisiert: habe einen schönen Beitrag für diese Angelegenheit gefunden: Beitrag

5
Lior Ohana

Der einzige Weg, um festzustellen, ob das andere Ende einer Socket-Verbindung noch verbunden ist oder nicht, besteht darin, das Ergebnis einer Lese- oder Schreiboperation oder möglicherweise eine Ausnahme abzufangen.

Weitere Informationen finden Sie in dieser StackOverflow-Frage: Sofortige Clientabtrennung vom Serversockel erkennen

Hier ist ein kleiner Codeausschnitt, der einfach eine Socket im nicht blockierenden Modus verwendet und mit einem Server verbunden ist.

                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 */
                }

Die von Lior Ohana vorgeschlagene "Keep-Alive" -Methode ist ebenfalls eine großartige Idee. Erzwingen Sie, dass jeder Client alle X Sekunden "eincheckt". Der Client kann feststellen, dass der Server nicht mehr vorhanden ist, wenn beim Schreiben eine Ausnahme auftritt, und der Server weiß, dass der Client nicht mehr vorhanden ist, wenn innerhalb von X Sekunden keine "Keep Alive" -Nachricht empfangen wurde. 

0
Chimera

Ich stimme mit Lior Ohana überein, weil ich dieses Problem mit Remote-Geräten hatte, die mit GPRS Tcp verbunden waren. Wenn das Gerät ausgeschaltet oder getrennt ist, wurde der Server nicht benachrichtigt. Dafür habe ich diesen Code verwendet: Ich schicke den Kunden bestimmte Zeit

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
        {

        }
    }
0
Akbar Jafari