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