如何确定tcp是否已连接?

时间:2011-08-09 08:23:54

标签: c# .net sockets networking tcp

我有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并尝试connecttoserver,因此服务器侦听器总是尝试在列表中添加客户端

4 个答案:

答案 0 :(得分:22)

请使用此代码,我已对其进行测试并在实际制作软件中使用它:

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中,并期望连接随时丢失!

答案 1 :(得分:5)

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

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

更新:发现了一个很好的帖子:Post

答案 2 :(得分:0)

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

有关更多信息,请参阅此StackOverflow问题: 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提出的“保持活力”方法也是一个好主意。强制每个客户每隔X秒“登记”一次。如果在写入时发生异常,则客户端可以检测到服务器已经消失,并且如果在X秒内没有接收到“保持活动”消息,则服务器知道客户端已经消失。

答案 3 :(得分:0)

我同意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
        {

        }
    }