名前付きパイプを使用して、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、パイプがビジーです。サーバーは、地獄がフリーズするか、サービスを再起動するまで、接続試行時にパイプ ビジー エラーを生成するようになりました。その後、再び 2 つの接続に戻ります。
私はこのコードを 3 日間連続して見つめてきましたが、なぜこれが行われるのかわかりません。木を見て木が見えないようで、新鮮な目を1つか3つ使うことができました。問題は、チームの誰もが C# の多くを知っていないことです。
アップデート
これが 3 回目の接続試行で失敗する理由は、最初の切断で PipeReadComplete が返され、0 バイトが読み取られるため、パイプを切り離すとすべてがうまくいくためです。しかし... 2回目の切断では、PipeReadCompleteは呼び出されないため、強制的に切断しません。変。