using Common.Attributes; using System.Net.Sockets; using System.Text; namespace DeviceCommand.Flexible { [ACPCommand] public static class FTCP { private static readonly SemaphoreSlim _commLock = new(1, 1); #region Send public static async Task SendAsync(string ipAddress,int port,int sendTimeout, byte[] buffer, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var client = new TcpClient(); client.SendTimeout = sendTimeout; await client.ConnectAsync(ipAddress, port, ct); using NetworkStream stream = client.GetStream(); await stream.WriteAsync(buffer, 0, buffer.Length, ct).WaitAsync(TimeSpan.FromMilliseconds(sendTimeout)); } finally { _commLock.Release(); } } public static Task SendAsync(string ipAddress, int port,int sendTimeout, string text,CancellationToken ct = default) { return SendAsync( ipAddress, port, sendTimeout, Encoding.UTF8.GetBytes(text),ct); } #endregion #region Read public static async Task ReadAsync(string ipAddress,int port,int receiveTimeout,int length,CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var client = new TcpClient(); client.ReceiveTimeout = receiveTimeout; await client.ConnectAsync(ipAddress, port, ct); using NetworkStream stream = client.GetStream(); byte[] buffer = new byte[length]; int offset = 0; using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); if (receiveTimeout > 0) cts.CancelAfter(receiveTimeout); while (offset < length) { int read = await stream.ReadAsync(buffer, offset, length - offset, cts.Token); if (read == 0) break; offset += read; } return buffer[..offset]; } finally { _commLock.Release(); } } public static async Task ReadLineAsync( string ipAddress, int port, int receiveTimeout, string delimiter = "\n",CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var client = new TcpClient(); client.ReceiveTimeout = receiveTimeout; await client.ConnectAsync(ipAddress, port, ct); using NetworkStream stream = client.GetStream(); var sb = new StringBuilder(); byte[] buffer = new byte[1024]; using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); if (receiveTimeout > 0) cts.CancelAfter(receiveTimeout); while (!cts.Token.IsCancellationRequested) { int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cts.Token); if (bytesRead == 0) break; sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)); int index = sb.ToString().IndexOf(delimiter, StringComparison.Ordinal); if (index >= 0) return sb.ToString(0, index).Trim(); } throw new TimeoutException("读取超时或对端关闭"); } finally { _commLock.Release(); } } #endregion } }