Java 中命名管道的并发读/写(在 Windows 上)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4974989/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 08:53:08  来源:igfitidea点击:

Concurrent read/write of named pipe in Java (on windows)

javamultithreadingdeadlocknamed-pipes

提问by takteek

I'm trying to provide communication between a C# app and a Java app on windows using named pipes with the method described by v01ver in this question: How to open a Windows named pipe from Java?

我正在尝试使用命名管道在 Windows 上的 C# 应用程序和 Java 应用程序之间提供通信,使用 v01ver 在这个问题中描述的方法:如何从 Java 打开 Windows 命名管道?

I'm running into a problem on the Java side because I have a reader thread constantly waiting for input on the pipe and when I try to write to the pipe from my main thread it gets stuck forever.

我在 Java 方面遇到了问题,因为我有一个读取器线程不断等待管道上的输入,当我尝试从主线程写入管道时,它会永远卡住。

final RandomAccessFile pipe;
try {
   pipe = new RandomAccessFile("\\.\pipe\mypipe", "rw");
}
catch (FileNotFoundException ex) {
   ex.printStackTrace();
   return;
}

Thread readerThread = new Thread(new Runnable() {
   @Override
   public void run() {
      String line = null;
      try {
         while (null != (line = pipe.readLine())) {
            System.out.println(line);
         }
      }
      catch (IOException ex) {
         ex.printStackTrace();
      }
   }
});
readerThread.start();

try { Thread.sleep(500); } catch (InterruptedException e) {}

try {
   System.out.println("Writing a message...");
   pipe.write("Hello there.\n".getBytes());
   System.out.println("Finished.");
}
catch (IOException ex) {
   ex.printStackTrace();
}

The output is:

输出是:

Writing a message...
然后它永远等待。

How can I write to a named pipe while waiting for input in another thread?

在另一个线程中等待输入时如何写入命名管道?

回答by Eagle

This is expected behaviour of pipes. It is supposed to hang untill other process connects to the pipe and reads it.

这是管道的预期行为。它应该挂起,直到其他进程连接到管道并读取它。

回答by Pa?lo Ebermann

I suppose that RandomAccessFileis not the right API here. Try a FileInputStream + FileOutputStream on the Java side. But that is only a guess, as I last used the Windows API in times when named pipes didn't yet exist.

我想这RandomAccessFile不是正确的 API。在 Java 端尝试 FileInputStream + FileOutputStream。但这只是一个猜测,因为我上次使用 Windows API 是在命名管道尚不存在的时候。

回答by Andrey

I have a same problem -- communication between a C#/Python app and a Java app on windows using named pipes:

我有同样的问题——使用命名管道在 Windows 上的 C#/Python 应用程序和 Java 应用程序之间进行通信:

We have example of Client Code written on Java, but in line String echoResponse = pipe.readLine();tread waits forever.

我们有用 Java 编写的客户端代码示例,但在队列中String echoResponse = pipe.readLine();永远等待。

try {
    // Connect to the pipe
    RandomAccessFile pipe = new RandomAccessFile("\\.\pipe\testpipe", "rw");
    String echoText = "Hello word\n";
    // write to pipe
    pipe.write ( echoText.getBytes() );
    // read response
    String echoResponse = pipe.readLine();
    System.out.println("Response: " + echoResponse );
    pipe.close();

    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

Solution of problem: I have a ServerPipe code written on Python from here Example Code - Named Pipes: and run its on Python 2.6.6

问题的解决方案:我有一个用 Python 编写的 ServerPipe 代码从这里示例代码 - 命名管道:并在 Python 2.6.6 上运行

from ctypes import *

PIPE_ACCESS_DUPLEX = 0x3
PIPE_TYPE_MESSAGE = 0x4
PIPE_READMODE_MESSAGE = 0x2
PIPE_WAIT = 0
PIPE_UNLIMITED_INSTANCES = 255
BUFSIZE = 4096
NMPWAIT_USE_DEFAULT_WAIT = 0
INVALID_HANDLE_VALUE = -1
ERROR_PIPE_CONNECTED = 535

MESSAGE = "Default answer from server
try {
    // Connect to the pipe
    RandomAccessFile pipe = new RandomAccessFile("\\.\pipe\mynamedpipe", "rw");
    String echoText = "Hello world\n";
    // write to pipe
    pipe.write(echoText.getBytes());

    //String aChar;
    StringBuffer fullString = new StringBuffer();

    while(true){
        int charCode = pipe.read();
        if(charCode == 0) break;
        //aChar = new Character((char)charCode).toString();
        fullString.append((char)charCode);
    }

    System.out.println("Response: " + fullString);
    pipe.close();
}
catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
" szPipename = "\\.\pipe\mynamedpipe" def ReadWrite_ClientPipe_Thread(hPipe): chBuf = create_string_buffer(BUFSIZE) cbRead = c_ulong(0) while 1: fSuccess = windll.kernel32.ReadFile(hPipe, chBuf, BUFSIZE, byref(cbRead), None) if ((fSuccess ==1) or (cbRead.value != 0)): print chBuf.value cbWritten = c_ulong(0) fSuccess = windll.kernel32.WriteFile(hPipe, c_char_p(MESSAGE), len(MESSAGE), byref(cbWritten), None ) else: break if ( (not fSuccess) or (len(MESSAGE) != cbWritten.value)): print "Could not reply to the client's request from the pipe" break else: print "Number of bytes written:", cbWritten.value windll.kernel32.FlushFileBuffers(hPipe) windll.kernel32.DisconnectNamedPipe(hPipe) windll.kernel32.CloseHandle(hPipe) return 0 def main(): THREADFUNC = CFUNCTYPE(c_int, c_int) thread_func = THREADFUNC(ReadWrite_ClientPipe_Thread) while 1: hPipe = windll.kernel32.CreateNamedPipeA(szPipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, NMPWAIT_USE_DEFAULT_WAIT, None ) if (hPipe == INVALID_HANDLE_VALUE): print "Error in creating Named Pipe" return 0 fConnected = windll.kernel32.ConnectNamedPipe(hPipe, None) if ((fConnected == 0) and (windll.kernel32.GetLastError() == ERROR_PIPE_CONNECTED)): fConnected = 1 if (fConnected == 1): dwThreadId = c_ulong(0) hThread = windll.kernel32.CreateThread(None, 0, thread_func, hPipe, 0, byref(dwThreadId)) if (hThread == -1): print "Create Thread failed" return 0 else: windll.kernel32.CloseHandle(hThread) else: print "Could not connect to the Named Pipe" windll.kernel32.CloseHandle(hPipe) return 0 if __name__ == "__main__": main()

After server have start you can use slightly modified version of the Java Client code:

服务器启动后,您可以使用稍微修改过的 Java 客户端代码版本:

##代码##

It works well in NetBeans 6.9.1.

它在 NetBeans 6.9.1 中运行良好。

回答by eckes

Don't worry, using RandomAccessFileto access a named pipeis correct. A named pipe is a file system object. Under Linux/Unix it is also called "fifo". Those objects are readable just like a file. (and not the same as pipes used between processes which are abstracted by Java Pipe class).

别担心,RandomAccessFile用于访问命名管道是正确的。命名管道是一个文件系统对象。在 Linux/Unix 下,它也被称为“fifo”。这些对象就像文件一样可读。(与由 Java Pipe 类抽象的进程之间使用的管道不同)。

However I see two problems with your program. I cannot test it currently as I would need your test server (feel free to publish). Your reader thread waits for answers from the other side (i.e. the server). It uses readLine(), I would use a different method (for debugging reading char by char might be the best).

但是我发现你的程序有两个问题。我目前无法测试它,因为我需要您的测试服务器(请随意发布)。您的阅读器线程等待来自另一端(即服务器)的答案。它使用 readLine(),我将使用不同的方法(用于调试按字符读取字符可能是最好的)。

With Java (without JNI) you cannot actually create a named pipe (server side). Opening a named pipe with the generic method used by RandomAccessFile you will get a byte-type stream which can be one-way or duplex.

使用 Java(没有 JNI),您实际上无法创建命名管道(服务器端)。使用 RandomAccessFile 使用的通用方法打开命名管道,您将获得一个字节类型的流,它可以是单向的或双工的。

BTW: JTDS (the free JDBC driver for SQL Server) can optionally use a named pipe to access SQL server, even over the network. And it is using exactly the RandomAccessFilemethod.

顺便说一句:JTDS(SQL Server 的免费 JDBC 驱动程序)可以选择使用命名管道来访问 SQL Server,甚至可以通过网络访问。它正在使用该RandomAccessFile方法。

BTW2: there is a makepipe.exe test server on older MS SQL Server installation media, however I did not find a trusted source to get that file.

顺便说一句:在较旧的 MS SQL Server 安装介质上有一个 makepipe.exe 测试服务器,但是我没有找到可信赖的来源来获取该文件。

回答by StanBell

I'm not familiar with JAVA, and my C# is pretty elementary too. However I'm had a similar problem with a multithreaded C++ client that I fixed by opening the pipe for overlapped IO. Until I did this, Windows serialized reads and writes, effectively causing an unsatisfied (blocking) ReadFile to prevent completion of a subsequent WriteFile until the read was done.

我不熟悉 JAVA,我的 C# 也很初级。但是,我在多线程 C++ 客户端上遇到了类似的问题,我通过打开重叠 IO 的管道来修复该问题。在我这样做之前,Windows 序列化读取和写入,有效地导致不满意(阻塞)ReadFile 以阻止后续 WriteFile 的完成,直到读取完成。

See CreateFile function
FILE_FLAG_OVERLAPPED

参见CreateFile 函数
FILE_FLAG_OVERLAPPED