我正在用C#开发一个服务器,它只能接受一个客户端,我需要知道这个客户端什么时候断开连接才能接受另一个连接请求。
我正在使用第一个Socket,它持续监听Socket.BeginAccept
的连接请求并接受或拒绝客户端。当接受客户端时,Socket.EndAccept
返回的新Socket用于客户端和服务器之间的通信。然后,服务器等待来自客户端Socket.Begin/EndReceive
的命令并发送响应。服务器使用类似Telnet的协议,这意味着每个命令和每行响应必须以\r\n
结尾。
为了检测客户端是否已断开连接,我安装了一个定时器,每500ms向客户端发送一条空消息(“\r\n
”)。如果客户端断开连接,则Socket会抛出异常。服务器捕获此异常,该服务器关闭当前会话并接受新连接。此解决方案是健壮的,但意味着网络上不需要的流量,必须由客户端正确处理,客户端必须在获得实际响应之前过滤虚拟消息。
我尝试发送一个空缓冲区(Socket.Send(new byte[1], 0, 0)
),但似乎无法在方向服务器 - >客户端中使用。
另一种解决方案可能是处理Socket.EndReceive
返回0字节的情况。它适用于在“空闲”时间内发生断开连接的情况。但是,如果客户端在传输消息期间断开连接,则服务器并不总是看到它并无限期地等待。
我已经看过几个关于这个问题的线索和问题,但我从未见过任何好的解决方案。
所以我的问题是:在.Net中检测断开连接的最佳方法是什么?
答案 0 :(得分:4)
唯一的另一个选择是,如果TCP是让TCP每隔一段时间发送一次保持活动,这仍然是轮询,例如你现在正在做什么但是在TCP层处理,所以你的协议没有'我需要知道。
轮询没有办法,但是因为没有向其他客户发送内容并得到回复,你无法知道它是否仍然连接。
通过状态数据包检查(如标准NAPT)进行通信时,无论如何都可能需要保持活动状态,以避免远程服务器因活动而丢弃会话。
答案 1 :(得分:3)
您可以使用以下方法查找客户端是否仍然连接。这个
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 :(得分:0)
您是否掌控了客户?如果是这样,你不能让客户端向服务器发送一个特殊的数据包,说它正在断开连接,然后断开套接字?
您是否尝试检测客户端实际已断开连接的情况(使用Socket.Shutdown()或Socket.Close())或客户端是否空闲了很长时间,因此需要喷出?
在任何一种情况下,让客户端向服务器发送定期消息(就像您一样)。服务器可以跟踪最后一次心跳,如果客户端错过超过3次心跳,则可以断开客户端连接。是的,它涉及额外的数据,但在宏观方案中这并不算太糟糕。如果你调整它以便它在足够长的时间内发送心跳,这样你就可以知道客户端是否还活着,并且心跳之间不会太长,你可以拥有一个非常好的系统。
答案 3 :(得分:0)