wxr
2024-12-02 ea0b1e8e5f43c5fd0a7d479e25ede3b8cbea464a
HDL_ON/DAL/DriverLayer/Control_TcpClient.cs
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using HDL_ON.Entity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -12,70 +9,13 @@
{
    public class Control_TcpClient
    {
        //声明IP,端口,和一个用来连接的Socket
        public string _ip;
        private string _ip;
        private TcpClient _clinet;
        private TcpClient _tcpClient {
            get
            {
                return _clinet;
            }
            set
            {
                _clinet = value;
                if (_clinet == null) {
                    if(connectThread!= null)
                    {
                        connectThread.Abort();
                        connectThread = null;
                    }
                }
            }
        }
        private bool run = true;
        private bool reconnect;
        //创建一个委托,用来满足其他类调用
        //public delegate void DelegateMessage(string str);
        public Action<string> ReceiveEvent;
        /// <summary>
        /// 连接次数
        /// </summary>
        private int reconnectIndex = 0;
        private bool _isConnected = false;
        /// <summary>
        /// 是否连接成功
        /// </summary>
        public bool isConnected {
            get
            {
                return _isConnected;
            }
            set
            {
                _isConnected = value;
                if (value)
                {
                    Control.Ins.LoginGateway();
                    HeartBeat();
                }
                else
                {
                    try
                    {
                        _tcpClient.Close();
                        _tcpClient = null;
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }
        private List<string> heartBeatLogIdList = new List<string>();
        /// <summary>
@@ -86,303 +26,216 @@
            heartBeatLogIdList.Clear();
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public Control_TcpClient(string serverIp)
        public Socket _socket;
        private string host;
        private int port;
        private static uint _keepAliveTime = 20 * 1000;      //无数据交互持续时间(ms)
        private static uint _keepAliveInterval = 500;   //发送探测包间隔(ms)
        private bool isInit;
        //构造函数
        public Control_TcpClient(string host, int port)
        {
            _ip = serverIp;
            this.host = host;
            this.port = port;
            reconnect = false;
        }
        //TCP连接
        private bool ConnectToTcp( )
        public void init()
        {
            if (string.IsNullOrEmpty(_ip) )
            if (isInit)
            {
                return false;
                return;
            }
            if (_tcpClient == null)
            {
                _tcpClient = new TcpClient();
            }
            isInit = true;
            connect();
            readFormSocket();
            reconnect2();
            heartBeat();
        }
        //连接
        private void connect()
        {
            try
            {
                _tcpClient.Connect(IPAddress.Parse(_ip), 8586);
                ReceiveMessage();//开启线程,不停接收消息
                MainPage.Log($"打开tcp client{_ip}:8586");
                isConnected = true;
                if (!run)
                {
                    return;
                }
                MainPage.Log("TcpClient->connect", $"开始连接,IP:{host}");
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _socket.Connect(host, port);
                reconnect = false;
                MainPage.Log("TcpClient->connect", $"连接成功,IP:{host}");
                //设置KeepAlive
                _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                byte[] optionValue = new byte[12];
                BitConverter.GetBytes(1).CopyTo(optionValue, 0);
                BitConverter.GetBytes(_keepAliveTime).CopyTo(optionValue, 4);
                BitConverter.GetBytes(_keepAliveInterval).CopyTo(optionValue, 8);
                _socket.IOControl(IOControlCode.KeepAliveValues, optionValue, null);
            }
            catch (Exception e)
            {
                MainPage.Log($"打开tcp异常:"+e.Message);
                return false;
            }
            return true;//返回连接状态
        }
        /// <summary>
        /// 连接tcp线程
        /// </summary>
        private Thread connectThread;
        /// <summary>
        /// 连接线程
        /// </summary>
        public void Connect()
        {
            lock (lockObj)
            {
                if (isConnected)
                {
                    return;
                }
                if (connectThread == null)
                {
                    connectThread = new Thread(() =>
                    {
                        while (Control.Ins.GatewayOnline_Local && !isConnected)
                        {
                            if (_tcpClient == null)
                            {
                                ConnectToTcp();
                            }
                            else
                            {
                                if (!_tcpClient.Connected)
                                {
                                    try
                                    {
                                        //_tcpClient.ReceiveTimeout =
                                        _tcpClient.Connect(IPAddress.Parse(_ip), 8586);
                                        ReceiveMessage();//开启线程,不停接收消息
                                        isConnected = true;
                                    }
                                    catch (Exception ex)
                                    {
                                        MainPage.Log($"tcp重连异常:{ex.Message}");
                                    }
                                }
                            }
                            Thread.Sleep(1000);
                        }
                    });
                    connectThread.Start();
                }
                else
                {
                    if (!isConnected)
                    {
                        try
                        {
                            connectThread?.Abort();
                        }
                        catch { }
                        finally
                        {
                            connectThread = null;
                        }
                        Connect();
                    }
                }
                MainPage.Log("TcpClient->connect", $"连接失败:{e.Message}");
            }
        }
        /// <summary>
        /// 重连
        /// </summary>
        public void Reconect()
        //发送数据接收实现,断线重连
        public int CommSend(byte[] buffer, int size)
        {
            if (_tcpClient == null)
            {
                Connect();
            }
            else
            {
                _tcpClient.Close();
                _tcpClient = null;
                Connect();
            }
        }
        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <returns></returns>
        public bool Close()
        {
            if (_tcpClient == null)
                return true;
            _tcpClient.Close();
            _tcpClient = null;
            return true;
        }
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="bytes">需要发送的字节</param>
        public void SendMessage(byte[] bytes)
        {
            if (heartBeatLogIdList.Count > 3)
            {
                try
                {
                    MainPage.Log("心跳多次未回复,断开tcp连接");
                    heartBeatLogIdList.Clear();
                    isConnected = false;
                    Reconect();
                    return;
                }catch (Exception ex)
                {
                    MainPage.Log($"重连tcp异常:{ex.Message}");
                }
            }
            int sendSize = 0;
            try
            {
                if (_tcpClient.GetStream().CanWrite&& isConnected)
                if (_socket.Connected)
                {
                    _tcpClient.GetStream().Write(bytes, 0, bytes.Length);
                    sendSize = _socket.Send(buffer, size, SocketFlags.None);
                }
            }catch(Exception ex)
            {
                MainPage.Log($"tcp客户端发送数据异常:{ex.Message}");
                isConnected = false;
            }
            catch (Exception e)
            {
                MainPage.Log("TcpClient->CommSend", $"发送失败,Data:{System.Text.Encoding.UTF8.GetString(buffer)} Exception:{e.Message}");
                //reconnect = true;
            }
            return sendSize;
        }
        /// <summary>
        /// 心跳包线程
        /// </summary>
        private Thread heartBeatThread;
        private DateTime heartBeatTime;
        public void HeartBeat()
        private void heartBeat()
        {
            lock (lockObj)
            new Thread(() =>
            {
                if (heartBeatThread == null)
                while (run)
                {
                    MainPage.Log($"心跳包线程启动");
                    heartBeatThread = new Thread(() =>
#if DEBUG
                    Thread.Sleep(2000);
#else
                        Thread.Sleep(3000);
#endif
                    if (UdpSocket._BusSocket.IsRunning)
                    {
                        while (isConnected)
                        if (10 * 1000 < (DateTime.Now - heartBeatTime).TotalMilliseconds)
                        {
                            if (_tcpClient.Connected && 10 * 1000 < (System.DateTime.Now - heartBeatTime).TotalMilliseconds)
                            {
                                string msgId = Control.Ins.msg_id.ToString();
                                heartBeatLogIdList.Add(msgId);
                                var sendJob = new JObject { { "id", Control.Ins.msg_id.ToString() }, { "time_stamp", Utlis.GetTimestamp() } };
                                var bodyString = JsonConvert.SerializeObject(sendJob);
                                var sendBytes = Control.Ins.ConvertSendBodyData(CommunicationTopic.ct.HeartBeat, bodyString, false);
                                SendMessage(sendBytes);
                                heartBeatTime = DateTime.Now;
                            }
                            Thread.Sleep(100);
                            string msgId = Control.Ins.msg_id.ToString();
                            heartBeatLogIdList.Add(msgId);
                            var sendJob = new JObject { { "id", Control.Ins.msg_id.ToString() }, { "time_stamp", Utlis.GetTimestamp() } };
                            var bodyString = JsonConvert.SerializeObject(sendJob);
                            var sendBytes = Control.Ins.ConvertSendBodyData(CommunicationTopic.ct.HeartBeat, bodyString, false);
                            CommSend(sendBytes, sendBytes.Length);
                            heartBeatTime = DateTime.Now;
                        }
                    });
                    heartBeatThread.Start();
                    }
                }
                else
            })
            { IsBackground = true }.Start();
        }
        //接收数据线程,使用阻塞方式接收数据
        private void readFormSocket()
        {
            new Thread(() =>
            {
                byte[] byteBuffer = new byte[1024 * 5];
                while (run)
                {
                    try
                    {
                        heartBeatThread?.Abort();
                        if (reconnect || !_socket.Connected)
                        {
                            Thread.Sleep(2000);
                            continue;
                        }
                        int len = _socket.Receive(byteBuffer, SocketFlags.None);
                        if (len == 0)
                        {
                            //已经断开
                            reconnect = true;
                        }
                        //  处理接收数据
                        var bytes = new byte[len];
                        Array.Copy(byteBuffer, 0, bytes, 0, bytes.Length);
                        LinkMessageDecoder.getInstance().Decoder(bytes, (dd, dd2) =>
                        {
                            Control.Ins.AnalysisReceiveData(dd, dd2);
                        });
                    }
                    catch (Exception ex)
                    catch (Exception e)
                    {
                        MainPage.Log($"启动心跳线程,重启线程异常:{ex.Message}");
                    }
                    finally
                    {
                        heartBeatThread = null;
                        HeartBeat();
                        MainPage.Log("TcpClient->ReadFormSocket", $"Exception:{e.Message}");
                        reconnect = true;
                    }
                }
            }
            })
            { IsBackground = true }.Start();
        }
        Thread reconnectThread;
        private void reconnect2()
        {
            reconnectThread = new Thread(() =>
            {
                while (run)
                {
                    Thread.Sleep(2000);
                    if (!run)
                    {
                        break;
                    }
                    if (reconnect)
                    {
                        close();
                        connect();
                    }
                }
            });
            reconnectThread.IsBackground = true;
            reconnectThread.Start();
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            run = false;
            close();
        }
        /// <summary>
        /// 接收数据线程
        /// 关闭
        /// </summary>
        private Thread receiveThread;
        private object lockObj = new object();
        //接收消息
        public void ReceiveMessage()
        private void close()
        {
            lock (lockObj)
            try
            {
                if (receiveThread == null)
                MainPage.Log("TcpClient->Close", $"Socket 关闭,IP:{host}");
                _socket.Close();
            }
            catch { }
        }
        /**
         * 获取数据的开始位置
         * @param arrayList 接收到的所有数据
         * @return 数据位的开始索引
         */
        int getDataIndex(List<byte> arrayList)
        {
            var r = (byte)'\r';
            var n = (byte)'\n';
            for (int i = 0; i < arrayList.Count; i++)
            {
                //找出数据内容前面的两个换行
                if (3 <= i && arrayList[i - 3] == r && arrayList[i - 2] == n && arrayList[i - 1] == r && arrayList[i] == n)
                {
                    receiveThread = new Thread(() =>
                    {
                        while (isConnected)
                        {
                            if (_tcpClient == null)
                            {
                                try
                                {
                                    receiveThread?.Abort();
                                }
                                catch { }
                                finally
                                {
                                    receiveThread = null;
                                }
                                return;
                            }
                            if (!_tcpClient.Connected)
                            {
                                MainPage.Log("tcp客户端断开了连接...");
                                isConnected = false;
                                return;
                            }
                            try
                            {
                                // 定义一个2M的缓存区;
                                byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                                try
                                {
                                    int size = _tcpClient.GetStream().Read(arrMsgRec, 0, arrMsgRec.Length);
                                }
                                catch (Exception ex)
                                {
                                    isConnected = false;
                                    MainPage.Log($"局域网tcp数据接收异常:{ex.Message}");
                                    return;
                                }
                                var tcpDataString = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, arrMsgRec.Length);
                                if (!string.IsNullOrEmpty(tcpDataString))
                                {
                                    MainPage.Log($"局域网tcp数据接收");
                                    Control.Ins.ConvertReceiveData(arrMsgRec, null);
                                }
                            }
                            catch (Exception) { }
                        }
                    });
                    //receiveThread.IsBackground = true;
                    receiveThread.Start();
                }
                else
                {
                    try
                    {
                        receiveThread?.Abort();
                    }
                    catch { }
                    finally
                    {
                        receiveThread = null;
                        ReceiveMessage();
                    }
                    //剩余的数据
                    return i + 1;
                }
            }
            return -1;
        }
    }