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

时间:2009-08-07 22:07:50

标签: c# named-pipes

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

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

在计时器滴答程序中,主要服务循环如下所示:

     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不会被调用,所以我不强制断开连接。怪异。

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

请参阅this related question以获取可能的答案。它看起来Suma经历并解决了同样的问题,而不是在C#中,它应该很容易翻译。