关于C# TCP断线重连的问题 百度谷歌后未能找到到满意答案 接着昨天的帖子

.Net技术 码拜 6年前 (2015-05-10) 573次浏览 0个评论

之前问过关于SP123大神关于c# tcp同步通讯+多线程的处理方式.通讯 接收 处理数据 都成功了,http://bbs.csdn.net/topics/391025405但是有一个问题,可能会发生网络掉线或者服务器设备损坏无法发出数据的问题。这个时候可能网线恢复或者设备重新开始工作后 我需要我这边的c# sokcte客户端能够重新连接,以下是我的解决思路,但是这样 数据会发生错位的解析处理,我不知道是不是我的思路不对,还是因为i线程池造成的问题,希望耐心看完代码解答一下 谢谢各位!

 static void Main(string[] args)
        {
            StarMain();
        }

        public static void StarMain()
        {
            foreach (Address address in Common.GetAddress())
            {
                ThreadPool.QueueUserWorkItem(h => SocketClient(address.IP, address.Port));
                Thread.Sleep(10);
            }
            Console.ReadLine();
        }

        /// <summary>
        /// 程序开始
        /// </summary>
        public static void SocketClient(string host, int port)
        {
            try
            {
                ByteQueue queue = new ByteQueue();
                IPAddress ip = IPAddress.Parse(host);
                IPEndPoint ipe = new IPEndPoint(ip, port);
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Connect(ipe);
                Console.WriteLine(ip + " Connected......");
                while (true)
                {
                    //建立缓冲区
                    byte[] recByte = new byte[4096];
                    int bytes = socket.Receive(recByte, recByte.Length, 0);

                    //分多次接收
                    byte[] reallData = new byte[bytes];
                    Array.Copy(recByte, reallData, reallData.Length);
                    queue.Enqueue(reallData);

                    //while可处理同时接收到多个包 防止一帧数据不是完整的包  
                    while (queue.Find())
                    {
                        byte[] readBuffer = queue.Dequeue();

                        //解析雷达数据 包含平均速度/占有率/车流量
                        string data = BitConverter.ToString(readBuffer);

                        if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                        {
                            GetData(data, host, port, DateTime.Now);
                        }
                        else if (data.StartsWith("0A 0B 0C 0D") && data.EndsWith("EA EB EC ED"))//历史数据
                        {
                            Regex regex = new Regex("0A 0B 0C 0D.{21}");
                            MatchCollection matches = regex.Matches(data, 0);
                            if (matches.Count > 0)
                            {
                                foreach (Match nextmach in matches)
                                {
                                    string history = nextmach.Value;
                                    string[] strTime = history.Split("" "");
                                    string year = strTime[0] + strTime[1];
                                    string moth = strTime[2];
                                    string day = strTime[3];
                                    string hh = strTime[4];
                                    string mm = strTime[5];
                                    string ss = strTime[6];
                                    DateTime time = Convert.ToDateTime(year + "-" + moth + "-" + day + " " + hh + ":" + mm + ":" + ss);
                                    GetData(data, host, port, time);
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine(data);
                        }
                    }
                }
            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine("ArgumentNullException: {0}", e.Message);
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e.Message);

                System.Timers.Timer t = new System.Timers.Timer(1000);   //实例化Timer类,设置间隔时间为10000毫秒;   
                t.Elapsed += new System.Timers.ElapsedEventHandler(theout); //到达时间的时候执行事件;   
                t.AutoReset = true;   //设置是执行一次(false)还是一直执行(true);   
                t.Enabled = true;     //是否执行System.Timers.Timer.Elapsed事件;  
            }
        }

        public static void theout(object source, System.Timers.ElapsedEventArgs e)
        {
            StarMain();
        }
同步或者异步对的客户端来说有什么区别呢?

或者是服务端根本没区别…所以你完全没必要纠结 我非得用同步+线程这样的方法..

因为异步比你这个高效的不是一个次元.

———————————–

本问题中..你是客户端还是服务端?

如果是客户端,你这代码是运行在你的”设备”中的?如果是这样try catch就可以捕获到”你”掉线或者”他”掉线.

掉线之后丢一个timer重新连接即可.

如果是服务端,客户端掉线你能捕获..你也只能捕获而已…….

————————————–

从你的代码来看是有问题的..因为一旦掉线之后  会1s出来一个timer 而且成倍的增长…1-2-4-8-16…..

所以要保证一个timer执行一次就释放了..或者只执行一次..

————————————-

另外顺便问下  你这是一个客户端连接N个服务端?

没我出场,看来就不行了!
可惜没时间
还有你重连不是这样写的。

把这个部份代码 抽出来,弄个一个方法 不要用 while (true) 去执行,应用异步 如果你坚持要用while true 那你上面的代码要改一下,不要再用时间去整这个。就是 int bytes = socket.Receive(recByte, recByte.Length, 0); 这个接收为0或内部出异常时,要结束while true 然后再延迟N秒进行重连。明白了么小明哥。


//建立缓冲区
                    byte[] recByte = new byte[4096];
                    int bytes = socket.Receive(recByte, recByte.Length, 0);
 
                    //分多次接收
                    byte[] reallData = new byte[bytes];
                    Array.Copy(recByte, reallData, reallData.Length);
                    queue.Enqueue(reallData);
 
                    //while可处理同时接收到多个包 防止一帧数据不是完整的包  
                    while (queue.Find())
                    {
                        byte[] readBuffer = queue.Dequeue();
 
                        //解析雷达数据 包含平均速度/占有率/车流量
                        string data = BitConverter.ToString(readBuffer);
 
                        if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                        {
                            GetData(data, host, port, DateTime.Now);
                        }
                        else if (data.StartsWith("0A 0B 0C 0D") && data.EndsWith("EA EB EC ED"))//历史数据
                        {
                            Regex regex = new Regex("0A 0B 0C 0D.{21}");
                            MatchCollection matches = regex.Matches(data, 0);
                            if (matches.Count > 0)
                            {
                                foreach (Match nextmach in matches)
                                {
                                    string history = nextmach.Value;
                                    string[] strTime = history.Split("" "");
                                    string year = strTime[0] + strTime[1];
                                    string moth = strTime[2];
                                    string day = strTime[3];
                                    string hh = strTime[4];
                                    string mm = strTime[5];
                                    string ss = strTime[6];
                                    DateTime time = Convert.ToDateTime(year + "-" + moth + "-" + day + " " + hh + ":" + mm + ":" + ss);
                                    GetData(data, host, port, time);
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine(data);
                        }
                    }

枪炮,你这是异步的方式,我上面是同步加多线程的处理啊

引用 1 楼 diaodiaop 的回复:

同步或者异步对的客户端来说有什么区别呢?

或者是服务端根本没区别…所以你完全没必要纠结 我非得用同步+线程这样的方法..

因为异步比你这个高效的不是一个次元.

———————————–

本问题中..你是客户端还是服务端?

如果是客户端,你这代码是运行在你的”设备”中的?如果是这样try catch就可以捕获到”你”掉线或者”他”掉线.

掉线之后丢一个timer重新连接即可.

如果是服务端,客户端掉线你能捕获..你也只能捕获而已…….

————————————–

从你的代码来看是有问题的..因为一旦掉线之后  会1s出来一个timer 而且成倍的增长…1-2-4-8-16…..

所以要保证一个timer执行一次就释放了..或者只执行一次..

————————————-

另外顺便问下  你这是一个客户端连接N个服务端?

对 是的 一个客户端对应N个服务器  由于网络环境局限 只能按照这种模式。

引用 2 楼 wyd1520 的回复:

没我出场,看来就不行了!
可惜没时间
还有你重连不是这样写的。

把这个部份代码 抽出来,弄个一个方法 不要用 while (true) 去执行,应用异步 如果你坚持要用while true 那你上面的代码要改一下,不要再用时间去整这个。就是 int bytes = socket.Receive(recByte, recByte.Length, 0); 这个接收为0或内部出异常时,要结束while true 然后再延迟N秒进行重连。明白了么小明哥。


//建立缓冲区
                    byte[] recByte = new byte[4096];
                    int bytes = socket.Receive(recByte, recByte.Length, 0);
 
                    //分多次接收
                    byte[] reallData = new byte[bytes];
                    Array.Copy(recByte, reallData, reallData.Length);
                    queue.Enqueue(reallData);
 
                    //while可处理同时接收到多个包 防止一帧数据不是完整的包  
                    while (queue.Find())
                    {
                        byte[] readBuffer = queue.Dequeue();
 
                        //解析雷达数据 包含平均速度/占有率/车流量
                        string data = BitConverter.ToString(readBuffer);
 
                        if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                        {
                            GetData(data, host, port, DateTime.Now);
                        }
                        else if (data.StartsWith("0A 0B 0C 0D") && data.EndsWith("EA EB EC ED"))//历史数据
                        {
                            Regex regex = new Regex("0A 0B 0C 0D.{21}");
                            MatchCollection matches = regex.Matches(data, 0);
                            if (matches.Count > 0)
                            {
                                foreach (Match nextmach in matches)
                                {
                                    string history = nextmach.Value;
                                    string[] strTime = history.Split("" "");
                                    string year = strTime[0] + strTime[1];
                                    string moth = strTime[2];
                                    string day = strTime[3];
                                    string hh = strTime[4];
                                    string mm = strTime[5];
                                    string ss = strTime[6];
                                    DateTime time = Convert.ToDateTime(year + "-" + moth + "-" + day + " " + hh + ":" + mm + ":" + ss);
                                    GetData(data, host, port, time);
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine(data);
                        }
                    }

异步我用过了 某些方面有局限 这种方式满足我的需求 不太懂你说的意思- -!

40分
引用 5 楼 SomethingJack 的回复:
Quote: 引用 2 楼 wyd1520 的回复:

没我出场,看来就不行了!
可惜没时间
还有你重连不是这样写的。

把这个部份代码 抽出来,弄个一个方法 不要用 while (true) 去执行,应用异步 如果你坚持要用while true 那你上面的代码要改一下,不要再用时间去整这个。就是 int bytes = socket.Receive(recByte, recByte.Length, 0); 这个接收为0或内部出异常时,要结束while true 然后再延迟N秒进行重连。明白了么小明哥。


//建立缓冲区
                    byte[] recByte = new byte[4096];
                    int bytes = socket.Receive(recByte, recByte.Length, 0);
 
                    //分多次接收
                    byte[] reallData = new byte[bytes];
                    Array.Copy(recByte, reallData, reallData.Length);
                    queue.Enqueue(reallData);
 
                    //while可处理同时接收到多个包 防止一帧数据不是完整的包  
                    while (queue.Find())
                    {
                        byte[] readBuffer = queue.Dequeue();
 
                        //解析雷达数据 包含平均速度/占有率/车流量
                        string data = BitConverter.ToString(readBuffer);
 
                        if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                        {
                            GetData(data, host, port, DateTime.Now);
                        }
                        else if (data.StartsWith("0A 0B 0C 0D") && data.EndsWith("EA EB EC ED"))//历史数据
                        {
                            Regex regex = new Regex("0A 0B 0C 0D.{21}");
                            MatchCollection matches = regex.Matches(data, 0);
                            if (matches.Count > 0)
                            {
                                foreach (Match nextmach in matches)
                                {
                                    string history = nextmach.Value;
                                    string[] strTime = history.Split("" "");
                                    string year = strTime[0] + strTime[1];
                                    string moth = strTime[2];
                                    string day = strTime[3];
                                    string hh = strTime[4];
                                    string mm = strTime[5];
                                    string ss = strTime[6];
                                    DateTime time = Convert.ToDateTime(year + "-" + moth + "-" + day + " " + hh + ":" + mm + ":" + ss);
                                    GetData(data, host, port, time);
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine(data);
                        }
                    }

异步我用过了 某些方面有局限 这种方式满足我的需求 不太懂你说的意思- -!

…你的需求与同步没有关系的。是你的代码方式的问题。

30分
线程是相当宝贵的资源。我的电脑创建2000个线程就到头了。

  int bytes = socket.Receive(recByte, recByte.Length, 0);//这个地方楼上说了,要判断0的问题。
但还有一个问题就是如果突然中间某相交换机或者某个线子出问题了。会一直卡在这的。(某些时候你需要两个小时以上才会收到异)
.StartsWith(“FF-FF-FF-FF-CA-CB-CC-CD”) 这样的判断也奇怪了。转换为字符判断这是在考验服务器嘛。

看你的代码粘包根本没有做处理。网络不堵塞的情况下还可以,如果出现堵塞。你根本收不到你想要的数据。
用正则表达式就是另一个不考虑效率的问题了。

30分
我一般另开个线程监视socket运行状态,如果状态不对,我就释放资源从新建立socket

不知道是否这个思路太过奔放

引用 7 楼 zanfeng 的回复:

线程是相当宝贵的资源。我的电脑创建2000个线程就到头了。

  int bytes = socket.Receive(recByte, recByte.Length, 0);//这个地方楼上说了,要判断0的问题。
但还有一个问题就是如果突然中间某相交换机或者某个线子出问题了。会一直卡在这的。(某些时候你需要两个小时以上才会收到异)
.StartsWith(“FF-FF-FF-FF-CA-CB-CC-CD”) 这样的判断也奇怪了。转换为字符判断这是在考验服务器嘛。

看你的代码粘包根本没有做处理。网络不堵塞的情况下还可以,如果出现堵塞。你根本收不到你想要的数据。
用正则表达式就是另一个不考虑效率的问题了。

字符串判断 和字节判断 服务器配置可以的 不考虑 再说这样做 测试过没有出现什么大问题 你的意思是说 直接用字节判断吧?

引用 8 楼 abutwang 的回复:

我一般另开个线程监视socket运行状态,如果状态不对,我就释放资源从新建立socket

不知道是否这个思路太过奔放

还有 粘包是在Queue类中处理的 


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于C# TCP断线重连的问题 百度谷歌后未能找到到满意答案 接着昨天的帖子
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!