BOB/DeviceCommand/Base/TCP.cs
2025-11-13 17:03:20 +08:00

170 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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