我尝试使用命名管道在Windows上的C#应用程序和Java应用程序之间提供通信,方法由v01ver在此问题中描述:How to open a Windows named pipe from Java?
我在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();
}
输出为:
Writing a message...
然后它永远等待。
如何在等待另一个线程中的输入时写入命名管道?
6条答案
按热度按时间evrscar21#
这是管道的预期行为。它应该挂起,直到其他进程连接到管道并读取它。
w8f9ii692#
我也遇到了同样的问题--在Windows上使用命名管道在C#/Python应用程序和Java应用程序之间进行通信:
我们有一个用Java编写的客户端代码的例子,但是在
String echoResponse = pipe.readLine();
行中,线程永远等待。问题解决方案:我有一个用Python写的ServerPipe代码,从这里Example Code - Named Pipes:并在Python 2.6.6上运行
服务器启动后,您可以使用Java客户端代码的稍微修改版本:
它在NetBeans 6.9.1中运行良好。
mrzz3bfm3#
我认为
RandomAccessFile
在这里不是正确的API。在Java端尝试FileInputStream + FileOutputStream。但这只是一个猜测,因为我上次使用Windows API时,命名管道还不存在。esbemjvw4#
不用担心,使用
RandomAccessFile
访问一个 named pipe 是正确的。命名管道是文件系统对象。在Linux/Unix下,它也被称为“fifo”。这些对象就像文件一样可读。(与Java Pipe类抽象的进程之间使用的管道不同)。但是我看到你的程序有两个问题。我不能测试它目前,因为我需要你的测试服务器(随时公布)。你的阅读器线程等待来自另一端的答案(即服务器)。它使用readLine(),我会使用不同的方法(对于调试阅读逐字符读取可能是最好的)。
使用Java(没有JNI),您实际上无法创建命名管道(服务器端)。使用RandomAccessFile使用的泛型方法打开命名管道,您将获得一个字节类型的流,该流可以是单向的,也可以是双向的。
顺便说一句:JTDS(SQL Server的免费JDBC驱动程序)可以选择使用命名管道访问SQL Server,甚至通过网络。它使用的正是
RandomAccessFile
方法。BTW 2:在旧的MS SQL Server安装介质上有一个makepipe.exe测试服务器,但是我没有找到一个可信的来源来获取该文件。
luaexgnf5#
管道是单向的意思,管道只能进行子到父的读操作和父到子的写操作,反之亦然,不能两者都做。为此,需要在C#和Java端使用两个管道,以便它们都执行读写操作。
管道与套接字:https://www.baeldung.com/cs/pipes-vs-sockets
[编辑]
因此,您无法在同一管道上执行读取和写入操作。一些语言如C#提供了双工管道,它可以在同一管道上执行读写操作,但可以肯定的是,这是两个管道“在引擎盖下”,分别用于读写操作。因此,只要是一个抽象,并且您并不真正知道“引擎盖下”发生了什么,您最好将两个管道之间的读写操作分段。另一个可能导致问题的因素是Java不能正式支持管道服务器,为了做到这一点,你需要使用Java Native Access库:RandomAccessFile Java实现使用OS文件系统以便在管道上执行读写操作,因此它具有一些限制,并且因此,如果两个线程正在访问存储器块,则在OS文件系统对象内异步地读写可能导致线程被锁定,并且甚至可能导致存储器损坏(竞争条件)。另一个问题是,当我试图从不同的线程对管道执行两个读操作时,我得到了
\\.\pipe\testpipe1 (All pipe instances are busy)
异常。这意味着,在您的场景中,您的管道可能很忙碌,并且在执行写操作时被锁定在等待响应状态。由于前面的因素,最好的选择是在管道上执行同步读/写操作,优选地使用两个管道,以便对所执行的读和写操作具有最大的控制。[C#应用]
[Java应用程序]
[ C#进程间通信结果]
[Java进程间通信结果]
emeijp436#
我对JAVA不太熟悉,我的C#也很初级。然而,我在一个多线程C++客户端上遇到了类似的问题,我通过打开重叠IO的管道来解决这个问题。在我这样做之前,Windows串行化了读取和写入,有效地导致了一个不满意(阻塞)的ReadFile,以防止后续WriteFile的完成,直到读取完成。
参见CreateFile function
文件_标志_重叠