| | |
| | | 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; |
| | | |
| | |
| | | { |
| | | 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> |
| | |
| | | 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; |
| | | MainPage.Log("TcpClient->connect", $"连接失败:{e.Message}"); |
| | | } |
| | | return true;//返回连接状态 |
| | | } |
| | | /// <summary> |
| | | /// 连接tcp线程 |
| | | /// </summary> |
| | | private Thread connectThread; |
| | | |
| | | /// <summary> |
| | | /// 连接线程 |
| | | /// </summary> |
| | | public void Connect() |
| | | //发送数据接收实现,断线重连 |
| | | public int CommSend(byte[] buffer, int size) |
| | | { |
| | | return; |
| | | 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) |
| | | { |
| | | int sendSize = 0; |
| | | try |
| | | { |
| | | //_tcpClient.ReceiveTimeout = |
| | | _tcpClient.Connect(IPAddress.Parse(_ip), 8586); |
| | | ReceiveMessage();//开启线程,不停接收消息 |
| | | isConnected = true; |
| | | } |
| | | catch (Exception ex) |
| | | if (_socket.Connected) |
| | | { |
| | | MainPage.Log($"tcp重连异常:{ex.Message}"); |
| | | sendSize = _socket.Send(buffer, size, SocketFlags.None); |
| | | } |
| | | } |
| | | } |
| | | Thread.Sleep(1000); |
| | | |
| | | |
| | | } |
| | | }); |
| | | connectThread.Start(); |
| | | } |
| | | else |
| | | catch (Exception e) |
| | | { |
| | | if (!isConnected) |
| | | { |
| | | try |
| | | { |
| | | connectThread?.Abort(); |
| | | MainPage.Log("TcpClient->CommSend", $"发送失败,Data:{System.Text.Encoding.UTF8.GetString(buffer)} Exception:{e.Message}"); |
| | | //reconnect = true; |
| | | } |
| | | catch { } |
| | | finally |
| | | { |
| | | connectThread = null; |
| | | return sendSize; |
| | | } |
| | | Connect(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 重连 |
| | | /// </summary> |
| | | public void Reconect() |
| | | { |
| | | 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) |
| | | { |
| | | return; |
| | | #if __IOS__ |
| | | |
| | | #endif |
| | | if (heartBeatLogIdList.Count > 3) |
| | | { |
| | | try |
| | | { |
| | | MainPage.Log("心跳多次未回复,断开tcp连接"); |
| | | heartBeatLogIdList.Clear(); |
| | | isConnected = false; |
| | | Reconect(); |
| | | return; |
| | | }catch (Exception ex) |
| | | { |
| | | MainPage.Log($"重连tcp异常:{ex.Message}"); |
| | | } |
| | | } |
| | | try |
| | | { |
| | | if (_tcpClient == null) |
| | | { |
| | | return; |
| | | } |
| | | if (!_tcpClient.Connected) |
| | | { |
| | | return; |
| | | } |
| | | if (_tcpClient.GetStream().CanWrite&& isConnected) |
| | | { |
| | | _tcpClient.GetStream().Write(bytes, 0, bytes.Length); |
| | | } |
| | | }catch(Exception ex) |
| | | { |
| | | MainPage.Log($"tcp客户端发送数据异常:{ex.Message}"); |
| | | isConnected = false; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 心跳包线程 |
| | | /// </summary> |
| | | private Thread heartBeatThread; |
| | | |
| | | private DateTime heartBeatTime; |
| | | public void HeartBeat() |
| | | private void heartBeat() |
| | | { |
| | | return; |
| | | 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 (_tcpClient.Connected && 10 * 1000 < (System.DateTime.Now - heartBeatTime).TotalMilliseconds) |
| | | if (10 * 1000 < (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); |
| | | CommSend(sendBytes, sendBytes.Length); |
| | | heartBeatTime = DateTime.Now; |
| | | } |
| | | Thread.Sleep(100); |
| | | } |
| | | }); |
| | | heartBeatThread.Start(); |
| | | } |
| | | else |
| | | }) |
| | | { IsBackground = true }.Start(); |
| | | } |
| | | |
| | | //接收数据线程,使用阻塞方式接收数据 |
| | | private void readFormSocket() |
| | | { |
| | | new Thread(() => |
| | | { |
| | | byte[] byteBuffer = new byte[1024 * 5]; |
| | | |
| | | while (run) |
| | | { |
| | | try |
| | | { |
| | | heartBeatThread?.Abort(); |
| | | } |
| | | catch (Exception ex) |
| | | if (reconnect || !_socket.Connected) |
| | | { |
| | | MainPage.Log($"启动心跳线程,重启线程异常:{ex.Message}"); |
| | | Thread.Sleep(2000); |
| | | continue; |
| | | } |
| | | finally |
| | | int len = _socket.Receive(byteBuffer, SocketFlags.None); |
| | | |
| | | if (len == 0) |
| | | { |
| | | if (heartBeatThread != null) |
| | | //已经断开 |
| | | reconnect = true; |
| | | } |
| | | |
| | | // 处理接收数据 |
| | | var bytes = new byte[len]; |
| | | Array.Copy(byteBuffer, 0, bytes, 0, bytes.Length); |
| | | LinkMessageDecoder.getInstance().Decoder(bytes, (dd, dd2) => |
| | | { |
| | | heartBeatThread = null; |
| | | Control.Ins.AnalysisReceiveData(dd, dd2); |
| | | }); |
| | | } |
| | | HeartBeat(); |
| | | catch (Exception e) |
| | | { |
| | | 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() |
| | | { |
| | | lock (lockObj) |
| | | { |
| | | if (receiveThread == null) |
| | | { |
| | | receiveThread = new Thread(() => |
| | | private void close() |
| | | { |
| | | try |
| | | { |
| | | while (isConnected) |
| | | { |
| | | if (_tcpClient == null) |
| | | { |
| | | try |
| | | { |
| | | receiveThread?.Abort(); |
| | | MainPage.Log("TcpClient->Close", $"Socket 关闭,IP:{host}"); |
| | | _socket.Close(); |
| | | } |
| | | 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)) |
| | | /** |
| | | * 获取数据的开始位置 |
| | | * @param arrayList 接收到的所有数据 |
| | | * @return 数据位的开始索引 |
| | | */ |
| | | int getDataIndex(List<byte> arrayList) |
| | | { |
| | | MainPage.Log($"局域网tcp数据接收"); |
| | | Control.Ins.ConvertReceiveData(arrMsgRec, null); |
| | | |
| | | } |
| | | } |
| | | catch (Exception) { } |
| | | } |
| | | }catch (Exception ex) |
| | | var r = (byte)'\r'; |
| | | var n = (byte)'\n'; |
| | | for (int i = 0; i < arrayList.Count; i++) |
| | | { |
| | | MainPage.Log($"tcp ReceiveMessage error :{ex.Message}"); |
| | | } |
| | | }); |
| | | //receiveThread.IsBackground = true; |
| | | receiveThread.Start(); |
| | | } |
| | | else |
| | | //找出数据内容前面的两个换行 |
| | | if (3 <= i && arrayList[i - 3] == r && arrayList[i - 2] == n && arrayList[i - 1] == r && arrayList[i] == n) |
| | | { |
| | | try |
| | | { |
| | | receiveThread?.Abort(); |
| | | } |
| | | catch { } |
| | | finally |
| | | { |
| | | receiveThread = null; |
| | | ReceiveMessage(); |
| | | //剩余的数据 |
| | | return i + 1; |
| | | } |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | } |