You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

608 lines
20 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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));
}
}
}