连接后如何测试TCPClient的连接断开? [英] How to test for a broken connection of TCPClient after being connected?

查看:25
本文介绍了连接后如何测试TCPClient的连接断开?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经与一个问题斗争了整整 3 天我找不到任何解决方案,请帮助 :)
我使用 Visual Studio 2010 和 C# 语言.

I've been fighting with one problem for a whole 3 days I can't find any solution, please help :)
I work with Visual Studio 2010 and C# language.

我有一个像服务器一样工作的设备,它会在非常不规则的时间段内发送一些数据(无法定义任何读取超时).
我编写了一个 TCP 客户端来连接到该服务器并读取数据.它工作正常,但是当网络出现问题并且服务器不可用时(例如,当我从计算机上拔下网线时),应用程序大约需要 10 秒才能注意到"没有与服务器的连接并抛出一个例外.(我不知道为什么正好是 10 秒?它在哪里定义的?我可以更改吗?)
我想更快地做出反应 - 假设在连接断开后一秒钟后.
然而,谷歌搜索答案并没有为我提供任何可行的解决方案.

I have a device working like a server, that sends some data in a very irregular periods of time (not possible to define any read timeout).
I wrote a TCP client to connect to that server and read data. It works OK, however when something is wrong with the network and server becomes unavailable (e.g. when I plug out the network cable from my computer), it takes about 10 seconds for application to "notice" there is no connection to the server and throw an exception. (I don't know why exactly 10 seconds? Where it's defined? Can I change it?)
I want to react faster - let say after one second after connection broken.
Googling for answer however doesn't provide me any working solution.

测试代码如下,我尝试在 2 个线程上进行:一个是读取数据,第二个是查找连接状态,当它损坏时应该提醒我.它不适用于 TCPClient 和 Socket 类.我尝试使用 tcpClient.SendTimeout = 100;stream.WriteTimeout = 100; 读取/写入一些数据,但它似乎不起作用.

The test code is below, I try to make it on 2 threads: one is reading data, the second one is looking for connection status and should alarm me when it's broken. It's not working neither for TCPClient nor Socket class. I've tried to read / write some data with tcpClient.SendTimeout = 100; and stream.WriteTimeout = 100; but it doesn't seem to work.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;

namespace TCPClient
{
    class Program
    {
        static volatile bool _continue = true;
        static TcpClient tcpClient;
        static NetworkStream stream;

        static void Main(string[] args)
        {
            try
            {
                //client thread - listen from server
                Thread tcpListenThread = new Thread(TcpListenThread);
                tcpListenThread.Start();

                //connection checking thread
                Thread keepAliveThread = new Thread(KeepAliveThread);
                keepAliveThread.Start();

                while (_continue)
                {
                    if (Console.ReadLine() == "q")
                    {
                        _continue = false;
                    }
                }

                keepAliveThread.Join(2000);
                if (keepAliveThread.IsAlive)
                {
                    Console.WriteLine("Thread keepAlive has been aborted...");
                    keepAliveThread.Abort();
                }

                tcpListenThread.Join(2000);
                if (tcpListenThread.IsAlive)
                {
                    Console.WriteLine("Listen thread has been aborted...");
                    tcpListenThread.Abort();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("
" + ex.Message);
            }

            Console.WriteLine("
Hit any key to quit...");
            Console.Read();
        }

        private static void TcpListenThread()
        {
            string server = "172.20.30.40";
            int port = 3000;

            try
            {
                using (tcpClient = new TcpClient())
                {
                    tcpClient.Connect(server, port);

                    if (tcpClient.Connected)
                        Console.WriteLine("Successfully connected to server");

                    using (stream = tcpClient.GetStream())
                    {

                        while (_continue)
                        {
                            Byte[] data = new Byte[1024];
                            Int32 bytes = stream.Read(data, 0, data.Length);
                            string responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);

                            Console.WriteLine("Received: {0}, responseData);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Listen thread exception! " + ex.Message);
            }
        }


        private static void KeepAliveThread()
        {
            while (_continue)
            {
                if (tcpClient != null)
                {
                    try
                    {
                        //...what to put here to check or throw exception when server is not available??...
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Disconnected...");
                    }
                }

                Thread.Sleep(1000);  //test for connection every 1000ms
            }
        }
    }
}


@carsten 的回答:虽然看起来很有希望,但这个解决方案不起作用......
我为此做了最简单的测试应用程序:


@carsten's answer: although it looks promising, this solution do not work...
I made the simplest test application for that:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;

namespace TCPClientTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string server = "172.20.30.40";
                int port = 3000;

                using (TcpClient tcpClient = new TcpClient())
                {
                    tcpClient.Connect(server, port);

                    int i = 0;
                    while (true)
                    {
                        // This is how you can determine whether a socket is still connected.
                        bool blockingState = tcpClient.Client.Blocking;
                        try
                        {
                            byte[] tmp = new byte[1];

                            tcpClient.Client.Blocking = false;
                            tcpClient.Client.Send(tmp, 0, 0);
                            Console.WriteLine("Connected!");
                        }
                        catch (SocketException e)
                        {
                            // 10035 == WSAEWOULDBLOCK
                            if (e.NativeErrorCode.Equals(10035))
                                Console.WriteLine("Still Connected, but the Send would block");
                            else
                            {
                                Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
                            }
                        }
                        finally
                        {
                            tcpClient.Client.Blocking = blockingState;
                        }

                        Console.WriteLine("Connected: {0} ({1})", tcpClient.Client.Connected, i++);

                        Thread.Sleep(1000);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Global exception: {0}", ex.Message);
            }
        }
    }
}

结果如下,显示:

已连接!
已连接:正确

每隔一秒加上我的订单号.当我断开网线时,需要 8 秒才能开始打印:

plus my order number every one second. When I disconnect network cable, it takes 8 seconds to start printing:

断开连接:错误代码 10054!
已连接:错误

所以到了 8 秒我不知道连接丢失了.看起来 ping 是这里的最佳选择,但我将测试其他解决方案.

so by 8 seconds I'm not aware that the connection is lost. It looks like pinging is the best option here, yet I'll test another solutions.

推荐答案

简单的答案.你不能.Tcp 的制作方式不允许这样做.但是,实现此目的的正常方法是以比消息更短的间隔发送 ping.因此,假设每当您从服务器收到一条消息时,您就会启动一个倒计时 1 分钟的时钟,然后您发送一个ping"命令(如果您在此期间没有收到新消息).如果您在 30 秒内未收到对ping"的响应,则您认为连接已断开.

Simple answer. You can't. Tcp is made in a way which doesn't allow this. However, the normal way to achieve this is to send ping's with shorter interval than messages. So, say, that whenever you get a message from the server, you start a clock that count down 1 min, then you send a "ping" command (if you haven't received a new message in between). If you don't receive a response to your "ping" within 30 seconds, you conclude that the connection is broken.

理论上,您应该能够在包级别执行此操作(tcp 发送您应该能够检查的 ACK),但我不知道这在 C# 或任何与此相关的编程语言中是否可行,或者如果您需要在固件/硬件中执行此操作.

Theoretically, you should be able to do this on a package-level (tcp sends ACK which you should be able to check for), but I don't know if that's possible in C#, or any programming language for that matter, or if you need to do that in firmware/hardware.

这篇关于连接后如何测试TCPClient的连接断开?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆