如何判断tcp是不是连接?

Posted

技术标签:

【中文标题】如何判断tcp是不是连接?【英文标题】:How to determine if the tcp is connected or not?如何判断tcp是否连接? 【发布时间】:2011-10-23 00:36:52 【问题描述】:

我有 tcpclient 对象,我想确定它是否已连接。 我使用 tcpclient 的连接属性,但它返回最后一次操作的状态。所以它没有用。

然后我使用此代码:

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

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

但它不能正常工作。

有什么想法吗?


这是我在服务器端的代码:

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

这是客户端:

    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 
        
    

在客户端,IsConnected() 总是返回 false 并尝试连接服务器,因此服务器监听器总是尝试将客户端添加到列表中

【问题讨论】:

你打开SocketOptionName.KeepAlive了吗?我认为您必须打开它才能使您的代码正常工作。无论如何,你不需要这样做。一般的解决方案是考虑socket正在连接,如果socket操作失败,优雅地处理连接丢失。但如果你需要... 请阅读FAQ。 *** 不是论坛。 这是一个“类似论坛”的问题?无论如何,FAQ 根本没有提到论坛。 【参考方案1】:

改用这段代码,我已经测试过它并在实际生产软件中使用它:

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;
        
    

编辑:但是,您不能仅仅依靠检查连接,如果为真则继续,因为它在执行此属性时返回连接状态,例如在您检查IsConnected 并返回true 之后,当您处于通信过程中时,连接可能会在那里丢失!我们只是一开始就使用它来降低失败的概率,所以你必须将整个通信包装在一个 try/catch 中,并期望连接随时会丢失!

【讨论】:

感谢您的回答,但它不适用于我的所有客户。它们中的一些返回连接状态 false,尽管它们是真正连接的,并且有些工作正常。 客户端连接到服务器一次,然后一个计时器调用 IsConnected,如果它返回 false 客户端尝试再次连接。问题是该函数对于某些客户端总是返回 false ! 可能是其他地方的问题,您如何检查每个客户?我认为一种方法是在这里使用一种方法public bool IsConnected(TcpClient _tcpClient) 并在添加新客户端时添加客户端列表,然后在计时器检查foreach (TcpClient client in _clientsArray).. 你在做什么?还是每个客户端都有自己的计时器? 每个客户端都有自己的计时器来检查连接状态,因为它们尝试连接到服务器。和客户端程序都是一样的。但我不明白为什么只有其中一些总是返回 false 并一次又一次地尝试连接。永远不会返回 true! 好的,你的意思是每个客户都有一个单独的程序“应用程序”吗?【参考方案2】:

我建议不要使用此类方法。 在我看来,最好的方法是实施某种保活机制。 每隔 X 秒,发送一条小消息并等待答复。 您可能会在以下情况下断开连接: 1. 尝试发送保持活动消息时捕获异常(如果您是客户端)。 2. 您在一段时间内没有收到保持活动消息/响应。

我也建议不要指望内置的 TCP keep-alive,我发现它非常不可靠。

更新:找到了一个关于这个问题的好帖子:Post

【讨论】:

【参考方案3】:

了解套接字连接的另一端是否仍然连接的唯一方法是捕获读取或写入操作的结果,或者可能捕获异常。

有关更多信息,请参阅此 *** 问题: Instantly detect client disconnection from server socket

这是一小段代码,它只是在非阻塞模式下使用Socket 并连接到服务器。

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

Lior Ohana 提出的“keep-alive”方法也是一个好主意。强制每个客户端每 X 秒“签入”一次。如果写入时发生异常,客户端可以检测到服务器已消失,如果 X 秒内未收到“保持活动”消息,则服务器知道客户端已消失。

【讨论】:

【参考方案4】:

我同意 Lior Ohana 的观点,因为我在使用 GPRS Tcp 连接的远程设备上遇到了这个问题。当设备关闭或断开连接时,它不会向服务器发出警报。我在那里使用了这段代码:我向客户发送特定时间

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
        

        
    

【讨论】:

以上是关于如何判断tcp是不是连接?的主要内容,如果未能解决你的问题,请参考以下文章

如何判断是不是连接到网站[关闭]

TCP socket如何判断连接断开

TCP socket如何判断连接断开

C语言关于socket中如何判断客户端是不是与服务器保持连接

如何判断socket客户端连接断开

Linux中TCP通信中 send函数 如何判断 何时断开连接了