首页 文章

在.NET中检测客户端断开连接的最佳做法?

提问于
浏览
8

我正在用C#开发一个服务器,它只能接受一个客户端,我需要知道这个客户端什么时候断开连接才能接受另一个连接请求 .

我正在使用第一个Socket,它继续用 Socket.BeginAccept 监听连接请求并接受或拒绝客户端 . 当接受客户端时, Socket.EndAccept 返回的新Socket用于客户端和服务器之间的通信 . 然后,服务器等待来自客户端的命令 Socket.Begin/EndReceive 并发送响应 . 服务器使用类似Telnet的协议,这意味着每个命令和每行响应必须以 \r\n 结尾 .

为了检测客户端是否已断开连接,我安装了一个定时器,每500ms向客户端发送一条空消息(“ \r\n ”) . 如果客户端断开连接,则Socket会抛出异常 . 服务器捕获此异常,该服务器关闭当前会话并接受新连接 . 此解决方案是健壮的,但意味着网络上不需要的流量,必须由客户端正确处理,客户端必须在获得实际响应之前过滤虚拟消息 .

我试图发送一个空缓冲区( Socket.Send(new byte[1], 0, 0) ),但它似乎在方向server-> client中不起作用 .

另一种解决方案可能是处理 Socket.EndReceive 返回0字节的情况 . 它适用于在"idle"时间内发生断开连接的情况 . 但是如果客户端在传输消息期间断开连接,则服务器并不总是看到它并无限期地等待 .

我已经看过几个关于这个问题的线索和问题,但我从未见过任何好的解决方案 .

所以我的问题是:在.Net中检测断开连接的最佳方法是什么?

4 回答

  • 3

    唯一的另一个选择是,如果TCP是让TCP每隔一段时间发送一次保持活动,这仍然是轮询,例如你现在正在做什么但是在TCP层处理,所以你的协议不需要知道 .

    然而,由于没有向其他客户发送内容并得到回复,您无法知道它是否仍然连接,因此无法绕过轮询 .

    在通过状态数据包检查(例如标准NAPT)进行通信时,也可能需要保持活动状态,以避免远程服务器因活动而丢弃会话 .

  • 0

    您可以使用以下方法查找客户端是否仍然连接 . 这个

    public static bool IsConnected(this TcpClient client)
    {
        try
        {
            bool connected = !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0);
    
            return connected;
        }
        catch
        {
            return false;
        }
    }
    

    这个answer用于测试套接字,这就是我获取代码片段的方法 .

  • 0

    你有控制权的客户吗?如果是这样,你不能让客户端向服务器发送一个特殊的数据包,说它正在断开连接,然后断开套接字连接?

    您是否尝试检测客户端实际已断开连接的情况(使用Socket.Shutdown()或Socket.Close())或客户端是否空闲了很长时间,因此需要被弹出?

    在任何一种情况下,让客户端向服务器发送定期消息(就像您所做的那样) . 服务器可以跟踪最后一次心跳,如果客户端错过超过3次心跳,则可以断开客户端连接 . 是的,它涉及额外的数据,但在宏观方案中这并不算太糟糕 . 如果你调整它以便它在足够长的时间内发送心跳,这样你就可以知道客户端是否还活着,并且心跳之间不会太长,你可以拥有一个非常好的系统 .

相关问题