170 lines
6.1 KiB
C#
170 lines
6.1 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Net.Sockets;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace DeviceCommand.Base
|
||
{
|
||
public class Tcp
|
||
{
|
||
public string IPAddress { get; set; } = "127.0.0.1";
|
||
public int Port { get; set; } = 502;
|
||
public int SendTimeout { get; set; } = 3000;
|
||
public int ReceiveTimeout { get; set; } = 3000;
|
||
public TcpClient TcpClient { get; set; } = new();
|
||
|
||
public Tcp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
||
{
|
||
IPAddress = ipAddress;
|
||
Port = port;
|
||
SendTimeout = sendTimeout;
|
||
ReceiveTimeout = receiveTimeout;
|
||
return this;
|
||
}
|
||
|
||
public static void ChangeDeviceConfig(Tcp tcp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
||
{
|
||
tcp.IPAddress = ipAddress;
|
||
tcp.Port = port;
|
||
if (sendTimeout > 0) tcp.SendTimeout = sendTimeout;
|
||
if (receiveTimeout > 0) tcp.ReceiveTimeout = receiveTimeout;
|
||
}
|
||
|
||
public static async Task<bool> ConnectAsync(Tcp tcp, CancellationToken ct = default)
|
||
{
|
||
if (!tcp.TcpClient.Connected)
|
||
{
|
||
tcp.TcpClient.Close();
|
||
tcp.TcpClient.Dispose();
|
||
tcp.TcpClient = new TcpClient();
|
||
await tcp.TcpClient.ConnectAsync(tcp.IPAddress, tcp.Port, ct);
|
||
}
|
||
else
|
||
{
|
||
var remoteEndPoint = (IPEndPoint)tcp.TcpClient.Client.RemoteEndPoint!;
|
||
var ip = remoteEndPoint.Address.MapToIPv4().ToString();
|
||
bool isSameAddress = ip.Equals(tcp.IPAddress);
|
||
bool isSamePort = remoteEndPoint.Port == tcp.Port;
|
||
|
||
if (!isSameAddress || !isSamePort)
|
||
{
|
||
tcp.TcpClient.Close();
|
||
tcp.TcpClient.Dispose();
|
||
tcp.TcpClient = new TcpClient();
|
||
await tcp.TcpClient.ConnectAsync(tcp.IPAddress, tcp.Port, ct);
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public static void Close(Tcp tcp)
|
||
{
|
||
tcp.TcpClient.Close();
|
||
}
|
||
|
||
public static async Task SendAsync(Tcp tcp, byte[] bytes, CancellationToken ct = default)
|
||
{
|
||
var timeoutMs = tcp.SendTimeout;
|
||
if (timeoutMs <= 0)
|
||
{
|
||
await tcp.TcpClient.Client.SendAsync(bytes, ct);
|
||
return;
|
||
}
|
||
|
||
var sendTask = tcp.TcpClient.Client.SendAsync(bytes, ct).AsTask();
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
throw new TimeoutException($"TCP通讯异常:写入操作在 {timeoutMs} ms内未完成");
|
||
|
||
await sendTask;
|
||
}
|
||
|
||
public static async Task SendAsync(Tcp tcp, string str, CancellationToken ct = default)
|
||
{
|
||
await SendAsync(tcp, Encoding.UTF8.GetBytes(str), ct);
|
||
}
|
||
|
||
public static async Task<byte[]> ReadAsync(Tcp tcp, byte[] buffer, CancellationToken ct = default)
|
||
{
|
||
if (!tcp.TcpClient.Connected) return null;
|
||
|
||
var timeoutMs = tcp.ReceiveTimeout;
|
||
if (timeoutMs <= 0)
|
||
return await ReadBytes(tcp, buffer, ct);
|
||
|
||
var readTask = ReadBytes(tcp, buffer, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
throw new TimeoutException($"TCP通讯异常:读取操作在 {timeoutMs} ms内未完成");
|
||
|
||
return await readTask;
|
||
}
|
||
|
||
private static async Task<byte[]> ReadBytes(Tcp tcp, byte[] buffer, CancellationToken ct)
|
||
{
|
||
NetworkStream stream = tcp.TcpClient.GetStream();
|
||
int bytesRead = 0;
|
||
while (bytesRead < buffer.Length)
|
||
{
|
||
int read = await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead, ct);
|
||
if (read == 0) return null;
|
||
bytesRead += read;
|
||
}
|
||
return buffer;
|
||
}
|
||
|
||
public static async Task<string> ReadAsync(Tcp tcp, string delimiter = "\n", CancellationToken ct = default)
|
||
{
|
||
delimiter ??= "\n";
|
||
var timeoutMs = tcp.ReceiveTimeout;
|
||
if (timeoutMs <= 0)
|
||
return await ReadString(tcp, delimiter, ct);
|
||
|
||
var readTask = ReadString(tcp, delimiter, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
throw new TimeoutException($"TCP通讯异常:读取操作在 {timeoutMs} ms内未完成");
|
||
|
||
return await readTask;
|
||
}
|
||
|
||
private static async Task<string> ReadString(Tcp tcp, string delimiter, CancellationToken ct)
|
||
{
|
||
NetworkStream stream = tcp.TcpClient.GetStream();
|
||
MemoryStream memoryStream = new();
|
||
byte[] buffer = new byte[2048];
|
||
|
||
int bytesRead;
|
||
while ((bytesRead = await stream.ReadAsync(buffer, ct)) > 0)
|
||
{
|
||
memoryStream.Write(buffer, 0, bytesRead);
|
||
string data = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||
int lineEndIndex = data.IndexOf(delimiter);
|
||
if (lineEndIndex >= 0)
|
||
return data[..lineEndIndex].Trim();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public async Task<string> WriteRead(Tcp tcp, string str, string endstr, CancellationToken ct = default)
|
||
{
|
||
await SendAsync(tcp, str, ct);
|
||
return await ReadAsync(tcp, endstr, ct);
|
||
}
|
||
|
||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||
{
|
||
return await ConnectAsync(this, ct);
|
||
}
|
||
}
|
||
}
|