NamedPipeServerStream.EndWaitForConnection() 只是在使用时挂起

Posted

技术标签:

【中文标题】NamedPipeServerStream.EndWaitForConnection() 只是在使用时挂起【英文标题】:NamedPipeServerStream.EndWaitForConnection() just hangs when used 【发布时间】:2012-02-04 23:08:42 【问题描述】:

我第一次尝试使用命名管道。在找到here 的 MS 文档中,它指出:

EndWaitForConnection 每次调用都必须调用一次 开始等待连接。

所以我正在努力成为一名优秀的小程序员并遵循文档,但EndWaitForConnection() 在我使用它时会无限期挂起。

所以我将我的代码精简到最低限度,看看我是否可以隔离问题但没有骰子。我已经从我编写的课程中提取了以下代码。我已经对其进行了修改,使其开始等待管道连接,然后立即尝试停止等待该管道连接:

private void WaitForConnectionCallBack(IAsyncResult result)




public void Start()

    var tempPipe = new NamedPipeServerStream("TempPipe",
                                             PipeDirection.In,
                                             254, 
                                             PipeTransmissionMode.Message,
                                             PipeOptions.Asynchronous);

    IAsyncResult result = tempPipe.BeginWaitForConnection(
                                    new AsyncCallback(WaitForConnectionCallBack), this);

    tempPipe.EndWaitForConnection(result);  // <----- Hangs on this line right here


1) 为什么它挂在EndWaitForConnection() 上?如果我想在收到连接之前关闭我的服务器,我怎样才能从根本上取消这个BeginWaitForConnection() 回调?

2) 假设我没有上述问题。如果 2 个客户端试图快速连接到我的命名管道会发生什么?

我是否会为它们中的每一个获得回调调用,还是必须等待接收第一个连接通知然后快速调用EndWaitForConnection() 然后再次调用WaitForConnectionCallBack() 以再次开始监听下一个客户端?

对我来说,后者似乎是一种竞争条件,因为我可能没有足够快地设置连接侦听器。

【问题讨论】:

按照设计,该调用只能在您的回调方法 (WaitForConnectionCallBack) 中使用。您可以通过调用 tempPipe.Close() 来取消它。 是的,我自己也有过这个结论。我基本上发现调用 tempPipe.Close() 会立即移动回调例程,问题是,我确实将它设置为立即调用 EndWaitForConnection,但是由于管道到那时关闭,它会引发异常。所以我不得不围绕它包装一个 try 语句,并且在 catch 语句中什么都不做。这是正确的解决方案吗?关闭管道对我来说似乎有点草率,因为知道它会在你的回调中强制出现一个你必须捕获的异常。 @HansPassant 我只是在编写基本相同的东西,我也对回调中的ObjectDisposedException 感到惊讶。从什么时候开始处理异常是“预期”的做事方式?我不是说你错了,但这有意义吗?这是它应该工作的方式吗? 是的,完全正常。异步调用异常完成,异常说明了原因。不要像答案那样抓住它们,只抓住 ODE。 【参考方案1】:

因此,对我有用的解决方案的基本框架如下:

private void WaitForConnectionCallBack(IAsyncResult result)

    try
    
        PipeServer.EndWaitForConnection(result);

        /// ...
        /// Some arbitrary code
        /// ...
    
    catch
    
        // If the pipe is closed before a client ever connects,
        // EndWaitForConnection() will throw an exception.

        // If we are in here that is probably the case so just return.
        return;
    

这是服务器代码。

public void Start()

    var server= new NamedPipeServerStream("TempPipe", 
                                          PipeDirection.In,
                                          254, 
                                          PipeTransmissionMode.Message, 
                                          PipeOptions.Asynchronous);

    // If nothing ever connects, the callback will never be called.
    server.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), this);

    // ... arbitrary code

// EndWaitForConnection() was not the right answer here, it would just wait indefinitely
// if you called it.  As Hans Passant mention, its meant to be used in the callback. 
// Which it now is. Instead, we are going to close the pipe.  This will trigger 
// the callback to get called.  

// However, the EndWaitForConnection() that will excecute in the callback will fail
// with an exception since the pipe is closed by time it gets invoked, 
// thus you must capture it with a try/catch

    server.Close(); // <--- effectively closes our pipe and gets our 
                        //       BeginWaitForConnection() moving, even though any future 
                        //       operations on the pipe will fail.

【讨论】:

仅供参考有关使用Message 模式的其他信息,请参阅C# UnauthorizedAccessException when enabling MessageMode for read-only named pipe (NamedPipeClientStream class)。

以上是关于NamedPipeServerStream.EndWaitForConnection() 只是在使用时挂起的主要内容,如果未能解决你的问题,请参考以下文章