NamedPipeServerStream.EndWaitForConnection() just hangs when used
Asked Answered
M

1

12

I'm trying to use named pipes for the first time. In the MS documentation found here, it states that:

EndWaitForConnection must be called exactly once for every call to BeginWaitForConnection.

So I'm trying to be a good little programmer and follow documentation, but the EndWaitForConnection() just hangs indefinitely when I use it.

So I stripped down my code to a bare minimum so see if I could isolate the problem but no dice. I've pulled the following code out of a class I've written. I've modified it so that it begins waiting on a pipe connection then immediately tries to stop waiting on that pipe connection:

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) Why does it hang on EndWaitForConnection()? If I want to shut down my server before I've received a connection, how can I essentially cancel this BeginWaitForConnection() callback?

2) Let's suppose that I did not have the above mentioned problem. What happens if 2 clients try to connect to my named pipe very quickly?

Do I get a callback invocation for each of them, or do I have to wait to receive the first connection notification then quickly call EndWaitForConnection() then WaitForConnectionCallBack() again to start listening for the next client again?

The latter seems like a race condition to me, because I may not set up the connection listener fast enough.

Mandell answered 4/2, 2012 at 23:8 Comment(4)
By design, that call should only be used in your callback method (WaitForConnectionCallBack). You cancel it by calling tempPipe.Close().Madsen
Yes, I sort of happened upon that conclusion myself. I basically found that calling tempPipe.Close() gets the callback routine moving immediately, problem is, I did have it set up to immediately call EndWaitForConnection, but since the pipe is closed by then, it throws an exception. So i had to wrap a try statement around that and do nothing in the catch statement. Is this the correct solution? It seems a little sloppy to me to close the pipe, knowing it will force an exception in your callback that you'll have to catch.Mandell
@HansPassant I was just coding up essentially this same thing, and I too, was surprised by that ObjectDisposedException in the callback. Since when is handling an exception the "expected" way of doing things? I'm not saying you're wrong, but does this make sense? Is this the way it should work?Your
Yes, it is entirely normal. The async call completed abnormally, the exception says why. Don't catch them all like the answer did, only catch ODE.Madsen
M
10

So, a basic skeleton of the solution that is working for me is as follows:

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

Here is the Server code.

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.
}
Mandell answered 7/2, 2012 at 18:6 Comment(1)
FYI See C# UnauthorizedAccessException when enabling MessageMode for read-only named pipe (NamedPipeClientStream class) for other information on using Message mode.Halleyhalli

© 2022 - 2024 — McMap. All rights reserved.