Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NamedPipeServerStream.EndWaitForConnection() just hangs when used

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.

like image 925
Ultratrunks Avatar asked Feb 04 '12 23:02

Ultratrunks


1 Answers

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.
}
like image 149
Ultratrunks Avatar answered Oct 20 '22 10:10

Ultratrunks