8

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

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

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

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

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

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

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

4

4 回答 4

5

唯一的另一个选择是,如果是 TCP,则让 TCP 每隔一段时间发送一次保持活动状态,这仍在轮询,例如您现在正在执行的操作,但在 TCP 层进行处理,因此您的协议不需要知道。

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

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

于 2009-09-02T12:29:50.470 回答
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;
    }
}

这个答案是为了测试套接字,这就是我得到我的代码片段的方式。

于 2009-09-02T12:38:17.913 回答
0

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

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

在任何一种情况下,让客户端定期向服务器发送一条消息(就像您所做的那样)。服务端可以跟踪上次的心跳,如果客户端漏掉超过3个心跳,可以断开客户端。是的,它涉及额外的数据,但从总体上看,这并不算太糟糕。如果你调整它,让它在足够好的时间发送心跳,这样你就可以知道客户端是否还活着,并且心跳之间的间隔不要太长,你可以拥有一个非常好的系统。

于 2009-09-10T19:50:07.137 回答
0

请参阅http://social.msdn.microsoft.com/forums/en-US/netfxnetcom/thread/d5b6ae25-eac8-4e3d-9782-53059de04628/

于 2009-12-01T16:33:48.643 回答