私たちは、名前付きパイプを使用して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は呼び出されないので、強制的に切断しません。奇妙な。
すでに見ました。私が見る限り、NamedPipeServerStreamには同等の呼び出しはありません。パイプストリームオブジェクトを破棄して再作成することを試行します。 –
説明:SetNamedPipeHandleStateに相当するものはありません。彼がやっているのは、パイプをNOWAITに変換して、新しい接続を待ってからWAITに戻すことだけです。私はすでに新しい接続を待っていますし、モード変更APIもありません。私は結論に達しています。これは、2000年代のIOCPラッパーAPIのように、実世界の障害シナリオに対応していないMSのスレッドプールAPIの別のケースです。私はスレッドを手に入れなければならないと思う。 –