using System;
|
using System.Collections.Generic;
|
using System.Net.Sockets;
|
using System.Threading;
|
using Newtonsoft.Json;
|
using Newtonsoft.Json.Linq;
|
|
namespace HDL_ON.DriverLayer
|
{
|
public class Control_TcpClient
|
{
|
//声明IP,端口,和一个用来连接的Socket
|
private string _ip;
|
|
private bool run = true;
|
private bool reconnect;
|
//创建一个委托,用来满足其他类调用
|
public Action<string> ReceiveEvent;
|
|
private List<string> heartBeatLogIdList = new List<string>();
|
/// <summary>
|
/// 心跳记录
|
/// </summary>
|
public void ClearHeartBeatLog()
|
{
|
heartBeatLogIdList.Clear();
|
}
|
|
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)
|
{
|
this.host = host;
|
this.port = port;
|
reconnect = false;
|
}
|
|
public void init()
|
{
|
if (isInit)
|
{
|
return;
|
}
|
isInit = true;
|
connect();
|
readFormSocket();
|
reconnect2();
|
heartBeat();
|
}
|
//连接
|
private void connect()
|
{
|
try
|
{
|
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("TcpClient->connect", $"连接失败:{e.Message}");
|
}
|
}
|
//发送数据接收实现,断线重连
|
public int CommSend(byte[] buffer, int size)
|
{
|
int sendSize = 0;
|
try
|
{
|
if (_socket.Connected)
|
{
|
sendSize = _socket.Send(buffer, size, SocketFlags.None);
|
}
|
}
|
catch (Exception e)
|
{
|
MainPage.Log("TcpClient->CommSend", $"发送失败,Data:{System.Text.Encoding.UTF8.GetString(buffer)} Exception:{e.Message}");
|
//reconnect = true;
|
}
|
return sendSize;
|
}
|
|
private DateTime heartBeatTime;
|
private void heartBeat()
|
{
|
new Thread(() =>
|
{
|
while (run)
|
{
|
#if DEBUG
|
Thread.Sleep(2000);
|
#else
|
Thread.Sleep(3000);
|
#endif
|
if (UdpSocket._BusSocket.IsRunning)
|
{
|
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);
|
CommSend(sendBytes, sendBytes.Length);
|
heartBeatTime = DateTime.Now;
|
}
|
}
|
}
|
})
|
{ IsBackground = true }.Start();
|
}
|
|
//接收数据线程,使用阻塞方式接收数据
|
private void readFormSocket()
|
{
|
new Thread(() =>
|
{
|
byte[] byteBuffer = new byte[1024 * 5];
|
|
while (run)
|
{
|
try
|
{
|
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 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 void close()
|
{
|
try
|
{
|
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)
|
{
|
//剩余的数据
|
return i + 1;
|
}
|
}
|
return -1;
|
}
|
|
}
|
}
|