0

我正在尝试让服务器允许 TCP 连接并回显正在发送的任何换行符分隔的消息。我希望多个客户端能够一个接一个地连接,保持相同的服务器套接字。这是我的代码:

TcpClient client;

while (true) {
    Console.Write("Waiting for connection... ");
    client = listener.AcceptTcpListener();
    nStream = client.GetStream();
    sReader = new StreamReader(nStream);
    Console.WriteLine("Connected!");

    while (client.Connected) {
        string line = sReader.ReadLine();
        Console.WriteLine(line);
    }
    Console.WriteLine("#Client Disconnected")
}

不幸的是,当远程客户端断开连接时,它永远不会逃脱“while (client.Connected)”循环。相反,我得到了对 STDOUT 的无限写入。

4

1 回答 1

3

基本上,您使用的 TcpClient.Connection 属性并没有按照您的想法执行。从 MSDN 文档:

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connected.aspx

因为 Connected 属性仅反映最近操作时的连接状态,所以您应该尝试发送或接收消息以确定当前状态。消息发送失败后,该属性不再返回true。请注意,此行为是设计使然。您无法可靠地测试连接的状态,因为在测试和发送/接收之间的时间内,连接可能已经丢失。

要点是属性 TcpClient.Connection 在主机断开连接后但在您的服务器阻止等待从流中读取另一行之前没有更新。在阻止之前,您需要一种更可靠的方法来检测连接是否处于活动状态。

原来,这个问题已经被问过了。因此,我从这里借用了答案并将其调整为您在 OP 中使用的格式。

https://stackoverflow.com/a/8631090

    static void Main(string[] args)
    {
        TcpClient client = new TcpClient();
        TcpListener listener = new TcpListener(IPAddress.Loopback, 60123);
        listener.Start();

        while (true)
        {
            Console.WriteLine("Waiting for connection...");
            client = listener.AcceptTcpClient();
            Console.WriteLine("Connection found");
            StreamReader reader = new StreamReader(client.GetStream());

            string line = string.Empty;
            while (TestConnection(client))
            {
                line = reader.ReadLine();
                Console.WriteLine(line);
            }
            Console.WriteLine("Disconnected");
        }
    }

    private static bool TestConnection(TcpClient client)
    {
        bool sConnected = true;

        if (client.Client.Poll(0, SelectMode.SelectRead))
        {
            if (!client.Connected) sConnected = false;
            else
            {
                byte[] b = new byte[1];
                try
                {
                    if (client.Client.Receive(b, SocketFlags.Peek) == 0)
                    {
                        // Client disconnected
                        sConnected = false;
                    }
                }
                catch { sConnected = false; }
            }
        }
        return sConnected;
    }

当我测试它时,这对我有用,它起作用的原因是在您尝试读取或写入连接之前,您无法判断连接是否关闭。您可以通过盲目地尝试读/写然后处理套接字关闭时出现的 IO 异常来做到这一点,或者您可以执行此测试器方法正在执行的操作并查看连接是否已关闭。

希望这可以帮助你

编辑

需要注意的是,这可能是也可能不是检查连接是否关闭的最有效的方法,但这纯粹是为了说明必须在服务器端通过读/写的方式自己检查连接,而不是依赖 TcpClient。联系。

编辑 2

我的样本没有很好地清理旧资源,向任何有强迫症反应的人道歉。

于 2012-12-09T04:23:34.820 回答