gpt4 book ai didi

java - 使用 JNI 的 Windows 命名管道的 Java 程序的 IPC

转载 作者:太空宇宙 更新时间:2023-11-03 23:21:39 35 4
gpt4 key购买 nike

我正在使用 JNI 创建一个 Java 类,它允许在不同的 Java 程序之间使用各种 IPC 机制。

我创建了一个名为 WindowsIPC 的类,其中包含一个可以访问 Windows 的命名管道 的 native 方法。我有一个名为 createNamedPipeServer() 的 native 函数,它调用 CreateNamedPipe。它似乎已正确创建管道,因为我可以使用 Process Explorer 等工具查看它。

我的问题是,当我在一个单独的 Java 程序中使用它并使用一个单独的线程使用 Java 的标准输入和输出流读取和写入数据时,它失败了。我可以向管道成功写入数据,但无法读取内容;它返回 FileNotFoundException(所有管道实例都忙)

我正在努力解决这个问题,因为我无法弄清楚还有什么其他进程正在使用该管道以及我在创建管道时指定了 PIPE_UNLIMITED_INSTANCES 的事实。我已经广泛阅读了读取的工作原理,我的直觉是 Java 中的输入/输出流会处理它,因为它会返回上述错误。

如有任何见解,我们将不胜感激。

代码如下:

WindowIPC.java

public class WindowsIPC {
public native int createNamedPipeServer(String pipeName);
static {
System.loadLibrary("WindowsIPC");
}
public static void main(String[] args) {
// some testing..
}
}

WindowsIPC.c

const jbyte *nameOfPipe; // global variable representing the named pipe
HANDLE pipeHandle; // global handle..

JNIEXPORT jint JNICALL Java_WindowsIPC_createNamedPipeServer
(JNIEnv * env, jobject obj, jstring pipeName) {
jint retval = 0;
char buffer[1024]; // data buffer of 1K
DWORD cbBytes;

// Get the name of the pipe
nameOfPipe = (*env)->GetStringUTFChars(env, pipeName, NULL);

pipeHandle = CreateNamedPipe (
nameOfPipe, // name of the pipe
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE |
PIPE_READMODE_BYTE |
PIPE_NOWAIT, // forces a return, so thread doesn't block
PIPE_UNLIMITED_INSTANCES,
1024,
1024,
0,
NULL
);

// error creating server
if (pipeHandle == INVALID_HANDLE_VALUE) retval = -1;
else printf("Server created successfully: name:%s\n", nameOfPipe);

// waits for a client -- currently in ASYC mode so returns immediately
jboolean clientConnected = ConnectNamedPipe(pipeHandle, NULL);

(*env)->ReleaseStringUTFChars(env, pipeName, nameOfPipe);
return retval;
}

最后是 TestWinIPC.java

import java.io.*;
import java.util.Scanner;
public class TestWinIPC {
public static void main (String[] args)
{

WindowsIPC winIPC = new WindowsIPC();

// TEST NAMED PIPES
final String pipeName = "\\\\.\\Pipe\\JavaPipe";

if (winIPC.createNamedPipeServer(pipeName) == 0) {
System.out.println("named pipe creation succeeded");
Thread t = new Thread(new NamedPipeThread(pipeName));
t.start();
try {
System.out.println("opening pipe for input");
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(pipeName)));
System.out.println("waiting to read");
String line = br.readLine();
System.out.println("Read from pipe OK: " + line);
br.close();
}
catch (IOException exc) {
System.err.println("I/O Error: " + exc);
exc.printStackTrace();
}

}
} //main

private static class NamedPipeThread implements Runnable {
private String pipeName;

public NamedPipeThread (String pipeName) {
this.pipeName = pipeName;
} // constructor

public void run () {
try {
PrintWriter pw = new PrintWriter(new FileOutputStream(pipeName));
pw.println("Hello Pipe");
System.out.println("Wrote to named pipe OK");
pw.close();
}
catch (IOException exc) {
System.err.println("I/O Error: " + exc);
exc.printStackTrace();
}
} // run
}
}

最佳答案

您收到“所有管道实例都忙”错误的原因是您两次连接到管道(一次用于读取,一次用于写入)但您只创建了一个实例。 (请注意,使用 PIPE_UNLIMITED_INSTANCES 选项允许您创建任意数量的实例,但您仍然必须自己创建它们。)

从表面上看,您期望调用 FileInputStream 以打开管道的服务器端。它不是这样工作的。您必须使用从 CreateNamedPipe 返回的句柄才能访问管道的服务器端。

在 JNI 中是否有一种直接的、受支持的方法将句柄转换为流我不知道(据我所知似乎没有)但请注意,它是一个非阻塞句柄可能会很复杂,因为 Java 几乎肯定不会想到这一点。

更有希望的方法是实现 InputStream 和/或 OutputStream 类,它们调用 JNI 方法来执行实际的 I/O。

附录:如果您不想使用 JNI,并且找不到任何更可接受的方式将 native 句柄转换为流,原则上您可以启动一个( native )线程将两个独立管道的服务器端连接在一起,允许客户端相互通信。我不确定这会比使用 JNI 执行得更好,但我认为它可能值得一试。


您的代码还有一个技术问题:在非阻塞模式下,您应该重复调用 ConnectNamedPipe 直到它报告管道已连接:

Note that a good connection between client and server exists only after the ERROR_PIPE_CONNECTED error is received.

在实践中,如果您不打算为另一个客户端重用管道实例,您可能不这样做就可以逃脱。 Windows 隐式连接任何给定管道实例的第一个客户端,因此您根本不需要调用 ConnectNamedPipe。但是,您应该注意,这是一个未记录的功能。

使用普通 I/O 并在 Java 代码第一次要求您执行 I/O 时发出对 ConnectNamedPipe 的调用可能更有意义;据推测,程序员会期望读取和/或写入操作无论如何都会阻塞。

如果您不想使用普通 I/O,您应该更喜欢异步 I/O 而不是非阻塞 I/O:

Nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0, and it should not be used to achieve asynchronous input and output (I/O) with named pipes.

(均引自 the MSDN page on ConnectNamedPipe .)

关于java - 使用 JNI 的 Windows 命名管道的 Java 程序的 IPC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37928125/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com