NamedPipeServerStream / async可靠的断开连接问题

我们使用命名管道在C#.Net服务和本机C ++应用程序之间进行通信。 该服务创建一个消息模式管道,然后启动计时器。

m_pipeServer = new NamedPipeServerStream ("Cyber_Srv_EventPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 4096, 4096, pipeSa); m_OutputQueue = new List(); 

在计时器中,tick例程是主服务循环,如下所示:

  do { if (!m_bClientAttached) { try { m_pipeServer.WaitForConnection (); m_bClientAttached = true; } catch (InvalidOperationException invope) { sDebug = string.Format ("Pipe wait exception InvOpEx: {0}", invope.Message); DebugMessage (sDebug); } } // the message-pumping part of the loop. if (m_bClientAttached) { try { if (!m_bReadInProgress) { m_bReadInProgress = true; m_pipeServer.BeginRead (byNewRead, 0, byNewRead.GetLength (0), new AsyncCallback (this.PipeReadComplete), m_iReadCount); } if (m_OutputQueue.Count () > 0) { if (!m_bWriteInProgress) { m_bWriteInProgress = true; My_Message opmsg = m_OutputQueue.ElementAt (0); m_pipeServer.BeginWrite (opmsg.ToByteArray (), 0, (int)(opmsg.MsgLength), new AsyncCallback (this.PipeWriteComplete), m_iWriteCount); } } } catch (IOException ioe) { sDebug = string.Format ("Main loop raised exception: {1}", ioe.Message); DebugMessage (sDebug); DetachClientPipe(); } Thread.Sleep(1); } } while (m_bRunning); m_pipeServer.Close (); } 

读写完成例程如下所示:

  private void PipeReadComplete (IAsyncResult iAR) { string sDebug; int iByteCount; My_Message ipmsg = new My_Message(); try { iByteCount = m_pipeServer.EndRead (iAR); if (iByteCount > 0) { ipmsg.FromByteArray(byNewRead); m_bReadInProgress = false; ... process message ... } else { try { DebugMessage ("PRC: Zero bytes read, disconnect pipe"); DetachClientPipe(); } catch (InvalidOperationException invope) { sDebug = string.Format ("PRC - Pipe disconnect exception: {0}", invope.Message); DebugMessage (sDebug); } } } catch (IOException e) { sDebug = string.Format ("PRC: Read {0} raised exception: {1}", (int)(iAR.AsyncState), e.Message); DebugMessage (sDebug); DetachClientPipe(); } } // ------------------------------------------------------------------ private void PipeWriteComplete (IAsyncResult iAR) { string sDebug; try { m_pipeServer.EndWrite (iAR); lock (m_OutputQueue) { m_OutputQueue.RemoveAt(0); } m_bWriteInProgress = false; } catch (IOException e) { sDebug = string.Format ("Write {0} raised exception: {1}", (int)(iAR.AsyncState), e.Message); DebugMessage (sDebug); DetachClientPipe(); } } // ------------------------------------------------------------------ private void DetachClientPipe() { if (m_pipeServer.IsConnected) { m_pipeServer.Disconnect(); } m_bClientAttached = false; } 

客户端代码是已知的好代码,可以重复使用。 所以这就是问题所在。 客户端可以正常连接。 然后我们关闭了客户端,一切都很好。 我们启动它并再次结合。 一切都很好,然后我们关闭它并再次启动它。 繁荣 – 错误231,管道忙。 服务器现在会在任何连接尝试时生成管道繁忙错误,直到地狱结束,或者我们重新启动服务。 然后我们又回到了两个连接。

我已经连续三天盯着这段代码,我不知道为什么会这样做。 我似乎无法看到木头的树木,我可以使用一双新眼睛或三只眼睛。 问题是没有 – 团队中的其他任何人都知道任何C#。

更新

在第三次连接尝试失败的原因似乎是在第一次断开连接时PipeReadComplete返回并且我得到零字节读取,所以我分离管道,一切都很好。 但是……在第二次断开连接时,PipeReadComplete不会被调用,因此我不强制断开连接。 奇怪的。

鲍勃,快速修复:想知道,您是否尝试过将服务器实例参数设置为1以上,看看它是否在2次尝试后仍然失败? 而不是1,放10,看它是否会有所帮助。 此外,如果您发布非托管代码也会有所帮助。 我目前正在做同样的事情,Windows服务加上非托管dll IPC。

  m_pipeServer = new NamedPipeServerStream ("Cyber_Srv_EventPipe", PipeDirection.InOut, 10, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 4096, 4096, pipeSa); 

或者您实际上只需要一个服务器管道实例?

有关可能的答案,请参阅此相关问题 。 看来Suma经历并解决了同样的问题,虽然不是在C#中,但翻译起来应该很容易。