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

问题描述:

我正在C#中开发一个服务器,它只能接受一个客户端,我需要知道这个客户端何时断开连接才能接受另一个连接请求。在.NET中检测客户端断开连接的最佳实践?

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

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

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

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

我已经看到了关于这个问题的几个线程和问题,但我从来没有见过任何好的解决方案。

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

唯一的其他选择是TCP是让TCP每隔一段时间发送一次keep-alive,这仍然是轮询,比如你正在做什么,但是在TCP层处理,所以你的协议不会不需要知道。

但是没有办法绕过轮询,因为如果不向其他客户端发送任何内容并获得响应,则无法知道它是否仍处于连接状态。

通过有状态数据包检测(如标准NAPT)进行通信时,保持活动状态可能也是必需的,以避免远程服务器由于活动中断而丢失会话。

+0

好的,我已经添加了使KeepAlive适用于我的套接字的代码。但是我现在期望的是什么?当客户端断开连接时,什么都不会发生......我希望在某处收到一个异常......我应该定期读或写一些东西吗? – cedrou 2009-09-02 20:46:20

+1

我虽然在使用Begin/EndReceive?如果是这样,则BeginReceive应该运行回调,并且当您调用EndReceive来获取结果时应该引发异常,或读取流0字节的末尾。 – 2009-09-02 22:51:54

+0

好吧,我现在得到一个异常...谢谢 – cedrou 2009-09-07 13:38:16

您可以使用下面的方法来查找客户端是否仍然连接。这

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是测试插座,这是我得到了我的代码段。

+2

如果客户端已经明确地关闭了连接,但是如果连接已经中断(例如电缆拔出),这种方法可以正常工作。 – cedrou 2009-09-02 12:44:11

+0

哪里是保持活着的地方,操作系统和TCP协议将处理定期消息给客户端,看看它是否活着,并且轮询套接字将检查本地状态。如果保持活动失败,套接字应报告不再连接。 – 2009-09-02 15:01:08

+0

尽管在使用异步Begin/EndReceive时,不应要求轮询,因为当套接字未能保持活动状态时,您应该收到具有错误的回调。 – 2009-09-02 15:01:55

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

您是否试图检测客户端实际已断开连接的情况(使用Socket.Shutdown()或Socket.Close())还是客户端闲置了大量时间,因此需要被推出?

在这两种情况下,让客户端向服务器发送一个定期的消息(就像你所做的那样)。服务器可以跟踪上一次检测信号,如果客户端错过了超过3次检测信号,则可以断开客户端连接。是的,它涉及额外的数据,但这在事物的宏伟计划中并不算太坏。如果您调整它以便在足够的时间内发送心跳信号,以便您了解客户是否还活着,并且在心跳之间不要太长时间,那么您可以拥有一个非常好的系统。