Reputation: 1682
I can't seem to find the answer anywhere, I'm trying to obtain a socket in Java, and hand over its file descriptor number so that I can use it in a C binary (the fd would be as argument).
I've obtained the FileDescriptor using reflection... but can't access the actual number anywhere.
I know other people have suggested JNI, but I'd like to keep it within Java if possible (and couldn't fully figure out how to do it)
Upvotes: 1
Views: 6987
Reputation: 28687
Stephen C's answer addresses how to get a FileDescriptor
, but here's a method to the file descriptor number from that object. On Windows, FileDescriptor
uses long handle
instead of int fd
internally, so this method first checks if handle
is used and returns that if so, otherwise it falls back to returning fd
. I haven't tested this with sockets as OP is using, but I imagine Windows
JVMs still use handle
.
public static long fileno(FileDescriptor fd) throws IOException {
try {
if (fd.valid()) {
// windows builds use long handle
long fileno = getFileDescriptorField(fd, "handle", false);
if (fileno != -1) {
return fileno;
}
// unix builds use int fd
return getFileDescriptorField(fd, "fd", true);
}
} catch (IllegalAccessException e) {
throw new IOException("unable to access handle/fd fields in FileDescriptor", e);
} catch (NoSuchFieldException e) {
throw new IOException("FileDescriptor in this JVM lacks handle/fd fields", e);
}
return -1;
}
private static long getFileDescriptorField(FileDescriptor fd, String fieldName, boolean isInt) throws NoSuchFieldException, IllegalAccessException {
Field field = FileDescriptor.class.getDeclaredField(fieldName);
field.setAccessible(true);
long value = isInt ? field.getInt(fd) : field.getLong(fd);
field.setAccessible(false);
return value;
}
Upvotes: 1
Reputation: 718826
In Java 7, you can cast a SocketInputStream
to a FileInputStream
, and call getFD()
to get the FileDescriptor
object.
Then you can use reflection to access the FileDescriptor object's private int fd
field. (You use the Class.getDeclaredField(...)
method to get the Field, call Field.setAccessible(true)
, and then get the field's value using Field.getInt(...)
.)
Beware that you may be making your code platform dependent by doing this. There are no guarantees that the particular private field will be present in older ... or forth-coming versions of Java, or in implementations of Java done by other vendors / suppliers.
Upvotes: 4