远程TCP连接时的C#

时间:2012-12-09 03:36:39

标签: c# tcpclient

我正在尝试让服务器允许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的无限写入。

1 个答案:

答案 0 :(得分: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.Connection上。

编辑2

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