using System.IO; using System.IO.Pipes; using System.Text; namespace DeviceService.Service.NamePipe { /// /// 命名管道客户端连接封装。 /// 每个实例对应管道服务端上的一条已建立连接,收发均通过 / 完成。 /// 协议约定:每条消息为一行 UTF-8 文本(以 \n 结尾),发送端单次写入“内容+换行”, /// 使 Message 模式下一条消息恰好是完整的一行。 /// public class NamePipeClient : IClient, IDisposable { /// 单条消息允许的最大字节数(16MB)。 internal const int MaxMessageLength = 16 * 1024 * 1024; /// 等待发送锁的超时时间(毫秒)。 private const int SendLockTimeout = 5000; /// 消息行结束符。StreamWriter 每次写入都会触发 AutoFlush,必须与内容在同一次 Write 中写入。 private const char LineEnding = '\n'; private readonly NamedPipeServerStream _stream; private readonly StreamWriter writer; private readonly StreamReader reader; private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1); private volatile bool _disposed; public NamePipeClient(NamedPipeServerStream serverStream) { var encoding = new UTF8Encoding(false); _stream = serverStream; reader = new StreamReader(serverStream, encoding, false, 1024, true); writer = new StreamWriter(serverStream, encoding, 1024, true) { AutoFlush = true }; } /// 连接是否仍然可用。 public bool IsConnected { get { if (_disposed) { return false; } return _stream.IsConnected; } } public bool Send(string data, out string msg) { if (data == null) { msg = "待发送的数据不能为空。"; return false; } return SendLine(data, Encoding.UTF8.GetByteCount(data) + 1, out msg); } public bool Send(byte[] data, out string msg) { if (data == null) { msg = "待发送的数据不能为空。"; return false; } // 负载按 UTF-8 文本处理,与行协议保持一致 return SendLine(Encoding.UTF8.GetString(data), data.Length + 1, out msg); } /// /// 写入一行消息。内容与换行符必须单次 Write 写入,配合 AutoFlush 才能成为一条完整消息。 /// private bool SendLine(string text, int byteLength, out string msg) { if (byteLength > MaxMessageLength) { msg = $"数据长度 {byteLength} 字节超过单条消息上限 {MaxMessageLength} 字节。"; return false; } if (_disposed) { msg = "管道连接已关闭,无法发送数据。"; return false; } if (!IsConnected) { msg = "管道连接已断开,无法发送数据。"; return false; } bool lockTaken = false; try { lockTaken = _sendLock.Wait(SendLockTimeout); if (!lockTaken) { msg = "发送超时:上一条数据仍未写出。"; return false; } // writer 非 thread-safe,统一由 _sendLock 串行化 writer.Write(text + LineEnding); writer.Flush(); msg = string.Empty; return true; } catch (Exception ex) { msg = $"发送失败:{ex.Message}"; return false; } finally { if (lockTaken) { _sendLock.Release(); } } } /// /// 读取一行消息。返回 null 表示对端已关闭连接。 /// internal async Task ReadMessageAsync() { if (_disposed) { return null; } string? line = await reader.ReadLineAsync().ConfigureAwait(false); return line; } public void Dispose() { if (_disposed) { return; } _disposed = true; try { reader.Dispose(); } catch { // 忽略关闭异常 } try { writer.Dispose(); } catch { // 忽略关闭异常 } try { _stream.Dispose(); } catch { // 关闭过程中的异常可以忽略 } _sendLock.Dispose(); } } }