|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Net.Sockets;
|
|
|
using System.Security.Cryptography;
|
|
|
using System.Text;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace Module.Socket.Tool
|
|
|
{
|
|
|
public class TcpClientChargerTool
|
|
|
{
|
|
|
#region 定义锁
|
|
|
private object lockObj = new object(); //线程同步锁
|
|
|
#endregion 定义锁
|
|
|
|
|
|
TcpClient ClientTcp = new TcpClient();
|
|
|
NetworkStream ClientStream = null;
|
|
|
private readonly object LockHandler = new object();
|
|
|
|
|
|
/// <summary>
|
|
|
/// 确定的已接收缓存字节数组
|
|
|
/// </summary>
|
|
|
private byte[] FixedBuffer;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 上次接收剩余字节
|
|
|
/// </summary>
|
|
|
private List<byte> RemainBuffer = new List<byte>();
|
|
|
|
|
|
/// <summary>
|
|
|
/// 缓存字节长度
|
|
|
/// </summary>
|
|
|
private int BufferSize;
|
|
|
/// <summary>
|
|
|
/// 客户端是否已经连接
|
|
|
/// </summary>
|
|
|
private bool IsConnected = false;
|
|
|
|
|
|
private Thread DataMonitoringThread = null;
|
|
|
private Thread ConnectMonitoringThread = null;
|
|
|
|
|
|
public event EventHandler<ViewLogEventArgs> ConnectedStatusChanged;
|
|
|
public event EventHandler<TcpDataReceivedEventArgs> DataReceived;
|
|
|
public event EventHandler<TcpDataSendEventArgs> DataSended;
|
|
|
|
|
|
private string _client_ip;
|
|
|
/// <summary>
|
|
|
/// 客户端IP地址
|
|
|
/// </summary>
|
|
|
public string F_ClientIP
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
return _client_ip;
|
|
|
}
|
|
|
set
|
|
|
{
|
|
|
lock (lockObj)
|
|
|
{
|
|
|
_client_ip = value;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private int _client_port;
|
|
|
/// <summary>
|
|
|
/// 客户端端口号
|
|
|
/// </summary>
|
|
|
public int F_ClientPort
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
return _client_port;
|
|
|
}
|
|
|
set
|
|
|
{
|
|
|
lock (lockObj)
|
|
|
{
|
|
|
_client_port = value;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 客户端任务线程是否已经开始运行
|
|
|
/// </summary>
|
|
|
public bool RaskThreadIsStart { get; set; } = true;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 数据接收事件是否被阻塞
|
|
|
/// </summary>
|
|
|
public bool DataReceivedEventIsSuspend { get; set; } = false;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 读数据超时时间(毫秒)
|
|
|
/// </summary>
|
|
|
public int ReadTimeout { get; set; } = 1000;
|
|
|
|
|
|
public TcpClientChargerTool() { }
|
|
|
|
|
|
public TcpClientChargerTool(string ipAddr, int port)
|
|
|
{
|
|
|
_client_ip = ipAddr;
|
|
|
_client_port = port;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 客户端连接
|
|
|
/// </summary>
|
|
|
public virtual void ClientConnect()
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
Disconnect();
|
|
|
ClientTcp.Connect(_client_ip, _client_port);
|
|
|
ClientStream = ClientTcp.GetStream();
|
|
|
|
|
|
bool state = ClientTcp.Connected;
|
|
|
if (state == false)
|
|
|
{
|
|
|
IsConnected = false;
|
|
|
SetConnectStatusEvent("连接失败");
|
|
|
TerminateThreadsTCPStream();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
IsConnected = true;
|
|
|
SetConnectStatusEvent("连接成功");
|
|
|
|
|
|
BufferSize = ClientTcp.ReceiveBufferSize;
|
|
|
FixedBuffer = new byte[BufferSize];
|
|
|
|
|
|
RaskThreadIsStart = true;
|
|
|
}
|
|
|
|
|
|
ConnectMonitoringThread = new Thread(MonitorConnecting);
|
|
|
ConnectMonitoringThread.Name = "TCP客户端连接状态监测" + _client_port.ToString();
|
|
|
ConnectMonitoringThread.Start();
|
|
|
|
|
|
DataMonitoringThread = new Thread(MonitorRecevingData);
|
|
|
DataMonitoringThread.Name = "TCP客户端数据接收监测" + _client_port.ToString();
|
|
|
DataMonitoringThread.Start();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
SetConnectStatusEvent("连接失败" + ex.ToString());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 设置连接状态字符串
|
|
|
/// </summary>
|
|
|
/// <param name="status">连接状态字符串。比如:“连接成功”</param>
|
|
|
private void SetConnectStatusEvent(string status)
|
|
|
{
|
|
|
string strClient = "";
|
|
|
if (ClientTcp != null && ClientTcp.Client.LocalEndPoint != null)
|
|
|
{
|
|
|
strClient = ClientTcp.Client.LocalEndPoint.ToString();
|
|
|
}
|
|
|
string strTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " ";
|
|
|
string strConnectLog = strTime + "客户端" + strClient + "与服务端" + _client_ip.ToString() + ":" + _client_port.ToString() + " " + status + "!";
|
|
|
|
|
|
EventHandler<ViewLogEventArgs> ConnectedHandler;
|
|
|
ConnectedHandler = ConnectedStatusChanged;
|
|
|
if (ConnectedHandler != null)
|
|
|
{
|
|
|
ConnectedHandler.Invoke(this, new ViewLogEventArgs() { ConnectedStatus = IsConnected, IsContent = strConnectLog });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 是否连接
|
|
|
/// </summary>
|
|
|
public bool Connected
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
bool state = ClientTcp.Connected;
|
|
|
|
|
|
if (state == false)
|
|
|
{
|
|
|
TerminateThreadsTCPStream();
|
|
|
}
|
|
|
if (state != IsConnected)
|
|
|
{
|
|
|
IsConnected = state;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
private set
|
|
|
{
|
|
|
if (value == IsConnected) return;
|
|
|
IsConnected = value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 断开连接
|
|
|
/// </summary>
|
|
|
public virtual void Disconnect()
|
|
|
{
|
|
|
TerminateThreadsTCPStream();
|
|
|
Connected = false;
|
|
|
|
|
|
ClientTcp.Close();
|
|
|
//ClientTcp.Dispose();
|
|
|
ClientTcp = new System.Net.Sockets.TcpClient();
|
|
|
|
|
|
//SetConnectStatusEvent("连接断开成功!");
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 结束线程与数据流
|
|
|
/// </summary>
|
|
|
private void TerminateThreadsTCPStream()
|
|
|
{
|
|
|
RaskThreadIsStart = false;
|
|
|
DataMonitoringThread = null;
|
|
|
ConnectMonitoringThread = null;
|
|
|
|
|
|
ClientStream?.Close();
|
|
|
ClientStream = null;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取客户端连接状态
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
private bool GetConnectedStatus()
|
|
|
{
|
|
|
return !((ClientTcp.Client.Poll(1000, SelectMode.SelectRead) && (ClientTcp.Client.Available == 0)) || !ClientTcp.Client.Connected);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 监测接收数据字符串
|
|
|
/// </summary>
|
|
|
|
|
|
private async void MonitorRecevingData()
|
|
|
{
|
|
|
await Task.Run(() =>
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
EventHandler<TcpDataReceivedEventArgs> DataReceivedHandler;
|
|
|
while (RaskThreadIsStart)
|
|
|
{
|
|
|
if (!Connected) ClientConnect();
|
|
|
else
|
|
|
{
|
|
|
DataReceivedHandler = DataReceived;
|
|
|
if (DataReceivedHandler != null)
|
|
|
{
|
|
|
if (ClientStream != null)
|
|
|
{
|
|
|
if (ClientStream.DataAvailable)
|
|
|
{
|
|
|
lock (LockHandler)
|
|
|
{
|
|
|
List<byte[]> datas = ReadOrigBytes();
|
|
|
if (datas != null)
|
|
|
{
|
|
|
if (datas.Count > 0)
|
|
|
{
|
|
|
for (int i = 0; i < datas.Count; i++)
|
|
|
{
|
|
|
if (datas[i].Length > 0)
|
|
|
{
|
|
|
DataReceivedHandler.Invoke(this, new TcpDataReceivedEventArgs() { Data = datas[i] });
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Thread.Sleep(2);
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Thread.Sleep(2);
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Thread.Sleep(2);
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Thread.Sleep(2);
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Thread.Sleep(2);
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Thread.Sleep(2);
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
ex.ToString();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 读原始数据字节数组--解析成数组类型的数据帧格式
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
private List<byte[]> ReadOrigBytes()
|
|
|
{
|
|
|
List<byte[]> bytesResult = new List<byte[]>();
|
|
|
if (ClientStream != null)
|
|
|
{
|
|
|
ClientStream.ReadTimeout = ReadTimeout;
|
|
|
while (true)
|
|
|
{
|
|
|
int readByte = 0;
|
|
|
try
|
|
|
{
|
|
|
readByte = ClientStream.Read(FixedBuffer, 0, BufferSize);
|
|
|
if (readByte == 0) break;
|
|
|
else if (readByte >= 9)
|
|
|
{
|
|
|
bytesResult = GetReadResult(FixedBuffer, readByte);
|
|
|
}
|
|
|
|
|
|
if (!ClientStream.DataAvailable) break;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
System.Diagnostics.Debug.WriteLine("警告: ReadRawBytes()引发异常: " + ex);
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return bytesResult;
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 监测客户端连接
|
|
|
/// </summary>
|
|
|
private void MonitorConnecting()
|
|
|
{
|
|
|
while (RaskThreadIsStart)
|
|
|
{
|
|
|
bool state = Connected;
|
|
|
|
|
|
if (state != IsConnected)
|
|
|
{
|
|
|
IsConnected = state;
|
|
|
if (state == false)
|
|
|
{
|
|
|
SetConnectStatusEvent("连接失败");
|
|
|
TerminateThreadsTCPStream();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
SetConnectStatusEvent("连接成功");
|
|
|
|
|
|
BufferSize = ClientTcp.ReceiveBufferSize;
|
|
|
FixedBuffer = new byte[BufferSize];
|
|
|
|
|
|
RaskThreadIsStart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Thread.Sleep(20);
|
|
|
}
|
|
|
}
|
|
|
public bool checksumDomainReceive(byte[] data)
|
|
|
{
|
|
|
bool bResult = false;
|
|
|
int checksum = 0;
|
|
|
|
|
|
for (int i = 6; i < data.Count() - 1; i++)//这里有校验域所以减一
|
|
|
{
|
|
|
checksum += data[i];
|
|
|
}
|
|
|
|
|
|
//foreach (byte b in data)
|
|
|
//{
|
|
|
// checksum += b;
|
|
|
//}
|
|
|
// 取校验和的低8位
|
|
|
byte b1 = (byte)(checksum & 0xFF);
|
|
|
byte b2 = data[data.Count() - 1];
|
|
|
if (data[data.Count() - 1] == (byte)(checksum & 0xFF))
|
|
|
bResult = true;
|
|
|
return bResult;
|
|
|
}
|
|
|
private List<byte[]> GetReadResult(byte[] bytes, int readLen)
|
|
|
{
|
|
|
List<byte[]> lstResult = new List<byte[]>();
|
|
|
|
|
|
{
|
|
|
byte[] bytesCppy = bytes;//操作此数组,不要动原始数组
|
|
|
|
|
|
//自定义解析 起始0xAA 0XF5-----会有很多包粘连到一起的情况
|
|
|
{
|
|
|
if (readLen >= 9)
|
|
|
{
|
|
|
for (int i = 0; i < readLen; i++)
|
|
|
{
|
|
|
if (i + 1 <= readLen)
|
|
|
{
|
|
|
if (bytes[i] == 0xAA && bytes[i + 1] == 0xF5)
|
|
|
{
|
|
|
if (i + 2 < readLen)
|
|
|
{
|
|
|
int leng = ToUInt16(bytesCppy, i + 2);//帧的长度
|
|
|
|
|
|
|
|
|
// 创建一个新的byte数组来存储截取的数据
|
|
|
byte[] newBytes = new byte[leng];
|
|
|
|
|
|
// 使用Array.Copy方法将原始数组中的一部分复制到新数组
|
|
|
Array.Copy(bytesCppy, i, newBytes, 0, leng);
|
|
|
|
|
|
//校验域是否正确
|
|
|
if (checksumDomainReceive(newBytes))
|
|
|
{
|
|
|
var info = newBytes[4];
|
|
|
if ((info & (1 << 1)) != 0)//AES加密
|
|
|
{
|
|
|
|
|
|
List<byte> byteList = newBytes.ToList();
|
|
|
byteList.Remove(8);
|
|
|
byteList.Remove(8);//移除前面两个长度
|
|
|
newBytes= byteList.ToArray();
|
|
|
lstResult.Add(newBytes);
|
|
|
}
|
|
|
else //不加密
|
|
|
{
|
|
|
lstResult.Add(newBytes);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
{
|
|
|
//int indexValue = 0;
|
|
|
//List<int> lstStartIndex = new List<int>(); //搜索开始字节0x68的索引值
|
|
|
//int len = 0;
|
|
|
//if (readLen >= 24)
|
|
|
//{
|
|
|
// for (int i = 0; i < readLen; i++)
|
|
|
// {
|
|
|
// if (bytes[i] == 0x68)
|
|
|
// {
|
|
|
// lstStartIndex.Add(i);
|
|
|
// }
|
|
|
// }
|
|
|
//}
|
|
|
//int indexNum = lstStartIndex.Count;
|
|
|
//if (indexNum > 0)
|
|
|
//{
|
|
|
// for (int j = 0; j < indexNum; j++)
|
|
|
// {
|
|
|
// indexValue = lstStartIndex[j];
|
|
|
// if (indexValue < bytes.Count())
|
|
|
// {
|
|
|
// if (j < indexNum - 1)
|
|
|
// {
|
|
|
// int datalen = lstStartIndex[j + 1] - lstStartIndex[j];
|
|
|
// //if (len == datalen)
|
|
|
// //{
|
|
|
// // indexValue += len;
|
|
|
// // byte[] data = new byte[datalen];
|
|
|
// // Array.Copy(bytes, lstStartIndex[j], data, 0, datalen);
|
|
|
// // lstResult.Add(data);
|
|
|
// //}
|
|
|
// //else
|
|
|
// //{
|
|
|
// // indexValue += len;
|
|
|
// // byte[] data = new byte[len];
|
|
|
// // if (len <= bytes.Count())
|
|
|
// // {
|
|
|
// // Array.Copy(bytes, lstStartIndex[j], data, 0, len);
|
|
|
// // lstResult.Add(data);
|
|
|
// // }
|
|
|
// //}
|
|
|
|
|
|
// byte[] data = new byte[datalen];
|
|
|
// if (len <= bytes.Count())
|
|
|
// {
|
|
|
// Array.Copy(bytes, lstStartIndex[j], data, 0, datalen);
|
|
|
// lstResult.Add(data);
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
// else
|
|
|
// {
|
|
|
// int datalen = readLen - lstStartIndex[j];
|
|
|
|
|
|
// byte[] data = new byte[datalen];
|
|
|
// Array.Copy(bytes, lstStartIndex[j], data, 0, datalen);
|
|
|
// lstResult.Add(data);
|
|
|
|
|
|
// }
|
|
|
// }
|
|
|
// }
|
|
|
//}
|
|
|
}
|
|
|
|
|
|
|
|
|
return lstResult;
|
|
|
}
|
|
|
|
|
|
///// <summary>
|
|
|
///// 客户端读字节
|
|
|
///// </summary>
|
|
|
///// <returns>字节数组</returns>
|
|
|
//public List<byte[]> ReadBytes()
|
|
|
//{
|
|
|
// lock (LockHandler)
|
|
|
// {
|
|
|
// if (!Connected) ClientConnect();
|
|
|
// return ReadOrigBytes();
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 客户端写字节指令
|
|
|
/// </summary>
|
|
|
/// <param name="dataBytes"></param>
|
|
|
public void Write(byte[] dataBytes)
|
|
|
{
|
|
|
if (ClientTcp != null)
|
|
|
{
|
|
|
if (ClientTcp.Connected)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
if (DataSended != null)
|
|
|
{
|
|
|
EventHandler<TcpDataSendEventArgs> DataSendHandler;
|
|
|
DataSendHandler = DataSended;
|
|
|
DataSendHandler.Invoke(this, new TcpDataSendEventArgs() { Data = dataBytes });
|
|
|
}
|
|
|
|
|
|
ClientStream.Write(dataBytes, 0, dataBytes.Length);
|
|
|
ClientStream.Flush();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
ex.ToString();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private bool disposedValue = false;
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
{
|
|
|
if (!disposedValue)
|
|
|
{
|
|
|
if (disposing)
|
|
|
{
|
|
|
TerminateThreadsTCPStream();
|
|
|
ClientTcp.Close();
|
|
|
ClientTcp = null;
|
|
|
}
|
|
|
|
|
|
disposedValue = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
{
|
|
|
Dispose(true);
|
|
|
}
|
|
|
|
|
|
private ushort ToUInt16(byte[] value, int offset)
|
|
|
{
|
|
|
return (ushort)(value[offset] + (value[offset + 1] << 8));
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|