我有一個Linux程序分爲兩部分。在Java中,如何從已打開的C套接字的文件描述符中獲取Socket或DatagramSocket?
一部分通過NAT遍歷來獲得UDP套接字(UDP hole punching)或TCP套接字(TCP hole punching)。第一部分是用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本地接口)或通過提供這種POD /結構的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;
}
如果Java代碼只需要關注連接的套接字,爲什麼Java代碼充滿了'ServerSocket?'的技巧? – EJP
如果我理解正確,是否要使用現有的打開套接字作爲底層套接字一個新的Java客戶端套接字? – perencia
可能的重複數據刪除:http://stackoverflow.com/questions/1243546/can-i-get-a-java-socket-from-a-file-descriptor-number –