NamedPipeServerStream/async 可靠断开问题
Posted
技术标签:
【中文标题】NamedPipeServerStream/async 可靠断开问题【英文标题】:NamedPipeServerStream/async reliable disconnect issues 【发布时间】:2009-08-07 22:07:49 【问题描述】:我们使用命名管道在 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;
客户端代码是已知的好代码,可重复使用。所以这就是问题所在。客户端可以正常连接。然后我们关闭了客户端,一切都很好。我们启动它并再次连接。一切都好,然后我们关闭它并重新启动它。 Boom - 错误 231,管道忙。服务器现在将在任何连接尝试上生成管道繁忙错误,直到地狱冻结,或者我们重新启动服务。然后我们再次回到两个连接。
我已经连续三天盯着这段代码了,我不知道为什么会这样。我似乎看不到树木只见树木,我可以用一三双新鲜的眼睛。问题是团队中没有其他人对任何 C# 了解很多。
更新
第三次连接尝试失败的原因似乎是在第一次断开连接时 PipeReadComplete 返回并且我读取了零字节,所以我分离了管道并且一切都很好。但是...在第二次断开连接时,不会调用 PipeReadComplete,因此我不会强制断开连接。很奇怪。
【问题讨论】:
【参考方案1】:Bob,快速修复:想知道,您是否尝试过将服务器实例参数设置为大于 1 并查看在 2 次尝试后是否仍然失败?而不是 1,而是 10,看看它是否会有所帮助。此外,如果您也发布非托管代码也会有所帮助。我目前也在做同样的事情,windows服务加非托管dll IPC。
m_pipeServer = new NamedPipeServerStream ("Cyber_Srv_EventPipe",
PipeDirection.InOut,
10,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous,
4096,
4096,
pipeSa);
或者您实际上始终只需要一个服务器管道实例?
【讨论】:
【参考方案2】:请参阅this related question 以获得可能的答案。 Suma 似乎遇到并解决了同样的问题,虽然不是在 C# 中,但它应该很容易翻译。
【讨论】:
已经看过了。据我所知,NamedPipeServerStream 没有等效的调用。我将尝试销毁和重新创建管道流对象。 澄清:没有等效的 SetNamedPipeHandleState。他所做的只是将管道转换为NOWAIT,等待新连接并将其设置回WAIT。我已经在等待新的连接并且我没有模式更改 API。我得出的结论是,这是 MS 的线程池 API 不处理实际故障场景的另一种情况,就像他们的 2000 年 IOCP 包装 API 没有处理一样。我想我得手工整理线程。以上是关于NamedPipeServerStream/async 可靠断开问题的主要内容,如果未能解决你的问题,请参考以下文章