我正在用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 回答
唯一的另一个选择是,如果TCP是让TCP每隔一段时间发送一次保持活动,这仍然是轮询,例如你现在正在做什么但是在TCP层处理,所以你的协议不需要知道 .
然而,由于没有向其他客户发送内容并得到回复,您无法知道它是否仍然连接,因此无法绕过轮询 .
在通过状态数据包检查(例如标准NAPT)进行通信时,也可能需要保持活动状态,以避免远程服务器因活动而丢弃会话 .
您可以使用以下方法查找客户端是否仍然连接 . 这个
这个answer用于测试套接字,这就是我获取代码片段的方法 .
你有控制权的客户吗?如果是这样,你不能让客户端向服务器发送一个特殊的数据包,说它正在断开连接,然后断开套接字连接?
您是否尝试检测客户端实际已断开连接的情况(使用Socket.Shutdown()或Socket.Close())或客户端是否空闲了很长时间,因此需要被弹出?
在任何一种情况下,让客户端向服务器发送定期消息(就像您所做的那样) . 服务器可以跟踪最后一次心跳,如果客户端错过超过3次心跳,则可以断开客户端连接 . 是的,它涉及额外的数据,但在宏观方案中这并不算太糟糕 . 如果你调整它以便它在足够长的时间内发送心跳,这样你就可以知道客户端是否还活着,并且心跳之间不会太长,你可以拥有一个非常好的系统 .
见http://social.msdn.microsoft.com/forums/en-US/netfxnetcom/thread/d5b6ae25-eac8-4e3d-9782-53059de04628/