目录
客户端代码
csharp
Task.Run(() =>
{
List<string> result = new List<string>();
try
{
using (var client = new NamedPipeClientStream(".", "MyTranslatePipe", PipeDirection.InOut))
{
// 记录连接开始(便于调试)
System.Diagnostics.Debug.WriteLine("NamedPipe: Connecting...");
// 5 秒超时(根据需要调整)
client.Connect(5000);
System.Diagnostics.Debug.WriteLine($"NamedPipe: Connected = {client.IsConnected}");
if (!client.IsConnected)
{
throw new InvalidOperationException("未能连接到命名管道。请确认服务已启动。");
}
// 明确使用不带 BOM 的 UTF8,避免可能的前导字节问题
var noBomUtf8 = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
// 使用 leaveOpen:true,避免 StreamReader/StreamWriter 在 Dispose 时关闭底层 pipe
using (var writer = new StreamWriter(client, noBomUtf8, bufferSize: 1024, leaveOpen: true) { AutoFlush = true })
using (var reader = new StreamReader(client, noBomUtf8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true))
{
System.Diagnostics.Debug.WriteLine("NamedPipe: Writing request...");
writer.WriteLine(json);
writer.Flush();
System.Diagnostics.Debug.WriteLine("NamedPipe: Waiting for response...");
// 阻塞读取一行响应(服务端必须 WriteLine 返回)
string resultJson = reader.ReadLine();
System.Diagnostics.Debug.WriteLine("NamedPipe: Received response");
if (string.IsNullOrEmpty(resultJson))
{
// 防护:避免反序列化 null 抛异常
result = new List<string>();
}
else
{
result = JsonConvert.DeserializeObject<List<string>>(resultJson) ?? new List<string>();
}
}
}
}
catch (Exception ex)
{
// 记录并用简单回退策略,不抛到 UI 线程导致不可预期的问题
System.Diagnostics.Debug.WriteLine("NamedPipe error: " + ex);
try
{
// 在 AutoCAD 环境建议用 Editor.WriteMessage 打日志(此处用 MessageBox 仅作提示)
System.Windows.MessageBox.Show("翻译服务通信失败:" + ex.Message, "提示");
}
catch { /* 若线程上下文不能弹窗则忽略 */ }
// 回退到原文,保证不会返回 null
result = texts.ToList();
}
return result;
});
服务端
csharp
using Newtonsoft.Json;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;
using TextTranslate;
Console.WriteLine("Named pipe server starting...");
string pipeName = "MyTranslatePipe";
// 使用异步主循环,持续接受客户端连接
while (true)
{
// 为每次连接创建新的 NamedPipeServerStream,但不要在外层 using,这样不会在启动后台任务后立即被释放
var server = new NamedPipeServerStream(
pipeName,
PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
Console.WriteLine("等待 .NET Framework 客户端连接...");
await server.WaitForConnectionAsync();
Console.WriteLine("客户端已连接。");
// 为当前连接启动一个后台任务来处理(任务内部负责释放 server)
_ = Task.Run(async () =>
{
// 将 server 的释放放到任务内部 using,确保后台任务结束后再释放
using (server)
{
try
{
var noBomUtf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
// 使用 leaveOpen:true,防止 reader/writer 在 Dispose 时关闭底层 NamedPipeServerStream
using var reader = new StreamReader(server, noBomUtf8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true);
using var writer = new StreamWriter(server, noBomUtf8, bufferSize: 1024, leaveOpen: true) { AutoFlush = true };
while (server.IsConnected)
{
string? request = await reader.ReadLineAsync();
if (request == null)
{
Console.WriteLine("客户端已断开连接(read null)。");
break;
}
if (string.IsNullOrEmpty(request) || request.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("收到退出指令,关闭连接。");
break;
}
Console.WriteLine($"收到请求: {request}");
string result = Translate(request);
await writer.WriteLineAsync(result);
Console.WriteLine($"返回结果: {result}");
}
// 确保所有写入被刷新到管道
try { writer.Flush(); } catch { }
}
catch (Exception ex)
{
Console.WriteLine("处理客户端时发生异常: " + ex);
}
finally
{
// 显式断开连接(断开前 reader/writer 已被 Dispose,但 leaveOpen:true 不会关闭底层 stream)
try { if (server.IsConnected) server.Disconnect(); } catch { }
Console.WriteLine("处理任务结束,准备接受下一个连接。");
}
}
});
}
static string Translate(string input)
{
TranslationRequest? translationRequest = JsonConvert.DeserializeObject<TranslationRequest>(input);
Task<List<string>> task = translationRequest.Texts.Translate(translationRequest.TargetLanguage);
task.Wait();
return JsonConvert.SerializeObject(task.Result);
//return JsonConvert.SerializeObject(new List<string>() { "苹果" });
}
// 内部请求模型(与服务端保持一致)
public class TranslationRequest
{
public List<string> Texts { get; set; }
public string TargetLanguage { get; set; }
}