多线程命名管道服务器并行处理请求异常问题排查
多线程命名管道服务器并行处理问题
我正在尝试创建一个可并行处理多个请求的多线程命名管道服务器,但运行行为不符合预期:当当前请求处于处理繁忙状态时,新请求会抛出"访问路径被拒绝"错误,直到当前执行线程释放。
代码实现
using Newtonsoft.Json; using System; using System.IO; using System.IO.Pipes; using System.Security.AccessControl; using System.Security.Principal; using System.Text; using System.Threading; namespace API.PipeServer { public class Server { private bool running; private Thread runningThread; private EventWaitHandle terminateHandle = new EventWaitHandle(false, EventResetMode.AutoReset); public string PipeName { get; set; } private void ServerLoop() { while (running) { ProcessNextClient(); } terminateHandle.Set(); } public void Run() { running = true; runningThread = new Thread(ServerLoop); runningThread.Start(); } public void Stop() { running = false; terminateHandle.WaitOne(); } public virtual string ProcessRequest(string message) { return ""; } public void ProcessClientThread(object o) { using (NamedPipeServerStream pipeStream = (NamedPipeServerStream)o) { StreamReader sr = new StreamReader(pipeStream); //Receive instruction message string instructionJson = sr.ReadLine(); Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: --- Receiving Instruction ---"); Console.WriteLine(instructionJson); //Getting instruction message var instruction = JsonConvert.DeserializeObject<InstructionHandler.Instruction>(instructionJson); //Get data var json = API.API.GetAPIJson(instruction); //Send data back to Python client try { pipeStream.Write(Encoding.UTF8.GetBytes(json)); pipeStream.WaitForPipeDrain(); } catch (Exception ex) { Console.WriteLine(ex); } Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: --- Closing Stream ---"); pipeStream.Close(); pipeStream.Dispose(); } } public void ProcessNextClient() { try { Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: Creating server"); PipeSecurity pipeSecurity = new PipeSecurity(); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow)); var pipeStream = NamedPipeServerStreamAcl.Create("test_api", PipeDirection.InOut, 254, PipeTransmissionMode.Message, PipeOptions.None, 1024, 1024, pipeSecurity); pipeStream.WaitForConnection(); //Spawn a new thread for each request and continue waiting Thread t = new Thread(ProcessClientThread); t.Start(pipeStream); } catch (Exception e) { Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: Error - {e.Message}"); } } } }
典型输出

问题分析与解决方法
1. 管道名格式错误
命名管道的标准格式应为\\.\pipe\管道名,直接使用"test_api"作为管道名,虽然系统会自动补全,但可能在多实例创建时引发路径识别问题,导致新连接无法创建实例。
修复:将管道创建代码中的名称改为标准格式:
var pipeStream = NamedPipeServerStreamAcl.Create(@"\\.\pipe\test_api", PipeDirection.InOut, 254, PipeTransmissionMode.Message, PipeOptions.None, 1024, 1024, pipeSecurity);
2. StreamReader导致底层流提前关闭
创建StreamReader时未指定leaveOpen: true,默认情况下StreamReader释放时会关闭底层的pipeStream,而using块又会再次释放管道流,导致双重释放,可能引发管道状态异常。
修复:创建StreamReader时添加leaveOpen: true参数:
StreamReader sr = new StreamReader(pipeStream, Encoding.UTF8, true, 1024, leaveOpen: true);
3. 多余的流释放代码
using块会自动处理pipeStream的释放,手动调用pipeStream.Close()和pipeStream.Dispose()属于重复操作,可能导致流状态异常。
修复:移除这两行代码:
// pipeStream.Close(); // pipeStream.Dispose();
4. 可选优化:使用ThreadPool替代手动创建线程
手动创建线程的开销较高,建议使用ThreadPool.QueueUserWorkItem或Task.Run来处理客户端连接,提升性能:
// 替换原线程创建代码 ThreadPool.QueueUserWorkItem(ProcessClientThread, pipeStream); // 或者使用Task Task.Run(() => ProcessClientThread(pipeStream));
内容的提问来源于stack exchange,提问作者ceds
相关产品推荐
相关产品推荐

