1

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)

6
  • 1
    AFAIK, you can't and even if you could, I don't see how you could "hand it over to" some other binary? Maybe if you posted what you are actually trying to do, there could be some alternatives? Commented Jul 12, 2012 at 16:09
  • 1
    I can, just done it and it works like a charm :) Commented Jul 12, 2012 at 16:36
  • It's generally meaningless to pass the descriptor number to another process - the same number in the other process doesn't necessarily refer to the same thing. How many processes on your system are using file descriptor 1 for stdout right now? Is stdout the same for all of them? Commented Jul 12, 2012 at 16:37
  • I was under the impression that calling the Exec method (Java Runtime) created a child process rather than a completely separate one, which would mean file descriptors would be shared. If that is not the case then I'll have to use JNI and the dup syscall. Commented Jul 12, 2012 at 16:56
  • Looks like it does something like a fork()/exec() (which inherits copies of the descriptors from the parent) but also closes everything but stdin,stdout, and stderr in the child. Commented Jul 12, 2012 at 17:24

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

6 Comments

doesn't really help the OP... and anyways, AFAIK, this doesn't expose the underlying socket fd.
@Nim - You will have to ask him ... but that is my intention. And have you looked at the source code before you start making pronouncements that it won't work? (Hint: I have.)
That's exactly what I wanted, I already had the FileDescriptor object, I just needed the fd field, but was looking at a depecrated version of the API (must have been) since it didn't show any private int fd field ... That's the native file descriptor right? If yes then tahanks!
@user1018513 - you have to look at the source code. It is a private field, and private fields are not shown in the Java SE javadocs. I looked at the Java 7 version ... and this may be different in other versions.
I've got a Socket object that's just been returned from ServerSocketChannel#socket()#accept(). When I call getInputStream() on it and try to cast that to a FileInputStream, I get a ClassCastException that the SocketAdaptor can't be cast: sun.nio.ch.SocketAdaptor$SocketInputStream cannot be cast to java.io.FileInputStream"
|
1

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;
}

1 Comment

ends up in FileDescriptor in this JVM lacks handle/fd field , any other clues ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.