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

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