如何确定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  -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,因此服务器侦听器总是尝试在列表中添加客户端

使用此代码,我已经测试了它并在真实的生产软件中使用它:

 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中包装整个通信,并期望连接随时丢失!

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

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

更新:找到了一个很好的post: 发布

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

有关更多信息,请参阅此StackOverflow问题: 立即检测客户端与服务器套接字的断开连接

这是一小段代码,它只是在非阻塞模式下使用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秒“登记”一次。 如果在写入时发生exception,则客户端可以检测到服务器已经消失,并且如果在X秒内没有接收到“保持活动”消息,则服务器知道客户端已经消失。

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