Named pipe is connected while checking if it exists from Java

I am using Lukas Thomsen's named pipe example to create a pipe server in C++ and a reader in Java.

On the Java side I want to wait until the Named Pipe is created by C++ server.

File file = new File("\\\\.\\pipe\\Pipe");

while(!file.exists());

InputStream input = new FileInputStream(file);

However, the file.exists() somehow connects the named pipe and instantiating FileInputStream throws following exception:

 java.io.FileNotFoundException: \\.\pipe\Pipe (All pipe instances are busy)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)

Here is the snippet of c++ server:

int main(void)
{
HANDLE hPipe;
char buffer[1024];
DWORD dwRead;


hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
                        PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,   // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
                        PIPE_WAIT,
                        1,
                        1024 * 16,
                        1024 * 16,
                        NMPWAIT_USE_DEFAULT_WAIT,
                        NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
    if (ConnectNamedPipe(hPipe, NULL) != FALSE)   // wait for someone to connect to the pipe
    {            
        cout<<"connected";
        //do amazing stuff after being connected.   
    }

    DisconnectNamedPipe(hPipe);
}

return 0;
}

So what it the proper way to wait for named pipe in Java without throwing this error?

Answers


The reason this problem occurs is that File.exists() on Windows is implemented using a sequence of native function calls to CreateFile, GetFileInformationByHandle and CloseHandle. See the getFileInformation function in the Java source code. From a named pipe perspective this is bad because on Windows named pipes have to be reset between uses and the CreateFile call in that native function counts as a use.

The solution is to ask forgiveness rather than permission when opening the named pipe on the Java side. Something along the lines of:

File file = new File("\\\\.\\pipe\\Pipe");

while (true) {
    try {
        return new FileInputStream(file);
    } catch (IOException e) {
        Thread.sleep(20);
    }
}

(Obviously you might not want to loop forever in practice, but the code in the question did.)


Need Your Help