命名管道已连接,同时检查它是否存在于 Java

Named pipe is connected while checking if it exists from Java

我正在使用 Lukas Thomsen's 命名管道示例在 C++ 中创建一个管道服务器,在 Java 中创建一个 reader。

在 Java 方面,我想等到 C++ 服务器创建命名管道。

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

while(!file.exists());

InputStream input = new FileInputStream(file);

但是,file.exists() 以某种方式连接命名管道并实例化 FileInputStream 抛出以下异常:

 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)

这是 c++ 服务器的片段:

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

那么在 Java 中等待命名管道而不抛出此错误的正确方法是什么?

出现此问题的原因是 Windows 上的 File.exists() 是使用对 CreateFile, GetFileInformationByHandle and CloseHandle. See the getFileInformation function in the Java source code 的一系列本机函数调用实现的。从命名管道的角度来看,这很糟糕,因为在 Windows 上,必须在使用之间重置命名管道,并且该本机函数中的 CreateFile 调用算作一次使用。

解决方案是在 Java 端打开命名管道时请求原谅而不是许可。大致如下:

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

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

(显然你可能不想在实践中永远循环,但问题中的代码确实如此。)