2009-08-07 35 views
0

私たちは、名前付きパイプを使用してC#.NetサービスとネイティブC++アプリケーション間の通信を行っています。サービスはメッセージモードパイプを作成し、タイマーを起動します。NamedPipeServerStream/async信頼性の高い切断問題

 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; 
    } 

クライアント側タイマーティックルーチンで

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

は次のようになり、メインサービスループであり、コードは良いコードとして知られており、再利用されています。だからここに問題がある。クライアントは正常に接続できます。その後、クライアントをシャットダウンし、すべて正常です。私たちはそれを始めると再びconect。すべてうまくいってから、それを閉じてもう一度始めます。ブームエラー231、パイプビジー。地獄が凍結するか、サービスを再開するまで、サーバーは接続試行時にパイプビジーエラーを生成します。それから2つの接続に戻ります。

私は3日連続でこのコードを見てきましたが、なぜこれがこれを行うのかわかりません。私は木の木を見ることができないようで、私は目や3つの新しい目を使うことができます。チームの誰もがC#の多くを知っているという問題は誰もありません。

更新

これが第三接続試行に失敗した理由は、それが最初の切断にPipeReadComplete戻りますように見えると私はゼロバイトが読み、私はパイプを切り離し、すべてが順調である得ます。しかし... 2番目の切断では、PipeReadCompleteは呼び出されないので、強制的に切断しません。奇妙な。

答えて

0

可能な回答はthis related questionを参照してください。 Sumaが同じ問題を経験し解決したようですが、C#ではなく、翻訳するのはかなり簡単です。

+0

すでに見ました。私が見る限り、NamedPipeServerStreamには同等の呼び出しはありません。パイプストリームオブジェクトを破棄して再作成することを試行します。 –

+0

説明:SetNamedPipeHandleStateに相当するものはありません。彼がやっているのは、パイプをNOWAITに変換して、新しい接続を待ってからWAITに戻すことだけです。私はすでに新しい接続を待っていますし、モード変更APIもありません。私は結論に達しています。これは、2000年代のIOCPラッパーAPIのように、実世界の障害シナリオに対応していないMSのスレッドプールAPIの別のケースです。私はスレッドを手に入れなければならないと思う。 –

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つのサーバーパイプインスタンスしか必要としませんか?

関連する問題