我有一个分为两个部分的Linux程序。
第一部分进行NAT遍历,以获取UDP套接字(UDP打洞)或TCP套接字(TCP打洞)。第一部分使用C编写,以便利用本地功能来促进或增强NAT遍历过程。第二部分实际上使用通过第一部分执行的NAT遍历获得的连接套接字。
现在问题来了。我希望第一部分(获取套接字的部分)与第二部分(将套接字用于特定应用程序目的的部分)相互独立。例如,我希望第一部分可重复使用于多种不同的应用程序,这些应用程序都需要在对等方之间建立UDP和TCP连接。
现在,我想让第二部分(应用程序部分)使用Java而不是C或C++编写。我希望第二部分使用由负责NAT遍历的C代码获得的套接字连接。假设第一部分建立了连接并返回了一个结构体:
代码似乎表明可能可以“在给定的文件描述符上重新创建绑定的{@link ServerSocket}”。这是否意味着也可以在给定的文件描述符上“重新创建绑定的{@link java.net.Socket}”?那么绑定的{@link java.net.DatagramSocket}呢?
第一部分进行NAT遍历,以获取UDP套接字(UDP打洞)或TCP套接字(TCP打洞)。第一部分使用C编写,以便利用本地功能来促进或增强NAT遍历过程。第二部分实际上使用通过第一部分执行的NAT遍历获得的连接套接字。
现在问题来了。我希望第一部分(获取套接字的部分)与第二部分(将套接字用于特定应用程序目的的部分)相互独立。例如,我希望第一部分可重复使用于多种不同的应用程序,这些应用程序都需要在对等方之间建立UDP和TCP连接。
现在,我想让第二部分(应用程序部分)使用Java而不是C或C++编写。我希望第二部分使用由负责NAT遍历的C代码获得的套接字连接。假设第一部分建立了连接并返回了一个结构体:
// Represents a TCP or UDP connection that was obtained in part one.
struct ConnectionObtained {
int socket_file_descriptor;
int source_port;
int destination_port;
int source_address; // 4 byte ipv4 address
int destination_address;
int is_UDP; // 1 for UDP client socket, 0 for TCP client socket
};
第一部分的C代码可以通过JNI(Java Native Interface)或进程间通信将此POD/struct提供给第二部分中的Java代码。
我希望Java代码使用该信息来构建一个声明类型为java.net.DatagramSocket或java.net.Socket的对象,并在任何期望DatagramSocket或Socket的位置使用该对象。
作为起点,请考虑以下示例代码...
/**
* Determines the Unix file descriptor number of the given {@link ServerSocket}.
*/
private int getUnixFileDescriptor(ServerSocket ss) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Field $impl=ss.getClass().getDeclaredField("impl");
$impl.setAccessible(true);
SocketImpl socketImpl=(SocketImpl)$impl.get(ss);
Method $getFileDescriptor=SocketImpl.class.getDeclaredMethod("getFileDescriptor");
$getFileDescriptor.setAccessible(true);
FileDescriptor fd=(FileDescriptor)$getFileDescriptor.invoke(socketImpl);
Field $fd=fd.getClass().getDeclaredField("fd");
$fd.setAccessible(true);
return (Integer)$fd.get(fd);
}
代码似乎表明可能可以“在给定的文件描述符上重新创建绑定的{@link ServerSocket}”。这是否意味着也可以在给定的文件描述符上“重新创建绑定的{@link java.net.Socket}”?那么绑定的{@link java.net.DatagramSocket}呢?
/**
* Recreates a bound {@link ServerSocket} on the given file descriptor.
*/
private ServerSocket recreateServerSocket(int fdn) throws Exception {
FileDescriptor fd=new FileDescriptor();
Field $fd=FileDescriptor.class.getDeclaredField("fd");
$fd.setAccessible(true);
$fd.set(fd,fdn);
Class $PlainSocketImpl=Class.forName("java.net.PlainSocketImpl");
Constructor $init=$PlainSocketImpl.getDeclaredConstructor(FileDescriptor.class);
$init.setAccessible(true);
SocketImpl socketImpl=(SocketImpl)$init.newInstance(fd);
ServerSocket ss=new ServerSocket();
ss.bind(new InetSocketAddress(0));
Field $impl=ServerSocket.class.getDeclaredField("impl");
$impl.setAccessible(true);
$impl.set(ss,socketImpl);
return ss;
}
ServerSocket
上的技巧? - user207421