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.

487 lines
16 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.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Module.Socket.Tool
{
public class TcpClientBmsTool
{
TcpClient ClientTcp = new TcpClient();
NetworkStream ClientStream;
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;
private Thread ConnectMonitoringThread;
public event EventHandler<ViewLogEventArgs> ConnectedStatusChanged;
public event EventHandler<TcpDataReceivedEventArgs> DataReceived;
public event EventHandler<TcpDataSendEventArgs> DataSended;
/// <summary>
/// 客户端IP地址
/// </summary>
public string ClientIP { get; set; }
/// <summary>
/// 客户端端口号
/// </summary>
public int ClientPort { get; set; }
/// <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 TcpClientBmsTool() { }
public TcpClientBmsTool(string ipAddr, int port)
{
ClientIP = ipAddr;
ClientPort = port;
}
/// <summary>
/// 客户端连接
/// </summary>
public virtual void ClientConnect()
{
try
{
Disconnect();
ClientTcp.Connect(ClientIP, ClientPort);
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客户端连接状态监测" + ClientPort.ToString();
ConnectMonitoringThread.Start();
DataMonitoringThread = new Thread(MonitorRecevingData);
DataMonitoringThread.Name = "TCP客户端数据接收监测" + ClientPort.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 + "与服务端" + ClientIP.ToString() + ":" + ClientPort.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 = new System.Net.Sockets.TcpClient();
}
/// <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(20);
continue;
}
}
}
else
{
Thread.Sleep(20);
continue;
}
}
else
{
Thread.Sleep(20);
continue;
}
}
}
else
{
Thread.Sleep(20);
continue;
}
}
else
{
Thread.Sleep(20);
continue;
}
}
else
{
Thread.Sleep(20);
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 > 6)
{
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);
}
}
private List<byte[]> GetReadResult(byte[] bytes, int readLen)
{
int indexValue = 0;
List<byte[]> lstResult = new List<byte[]>();
List<int> lstStartIndex = new List<int>(); //搜索开始字节0x08的索引值
int len = 0;
if (readLen >= 6)
{
for (int i = 0; i < readLen; i++)
{
if (bytes[i] == 0x88)
{
lstStartIndex.Add(i);
}
}
}
int indexNum = lstStartIndex.Count;
if (indexNum > 0)
{
for (int j = 0; j < indexNum; j++)
{
if (indexValue < bytes.Count())
{
//len = ToUInt16(bytes, indexValue + 1);
len = 13;
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);
}
}
}
else
{
int datalen = readLen - lstStartIndex[j];
if (len == datalen)
{
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
{
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));
}
}
}