将Java套接字文件描述符传递到C二进制文件的最有效方法

将Java套接字文件描述符传递到C二进制文件的最有效方法,java,c,sockets,java-native-interface,file-descriptor,Java,C,Sockets,Java Native Interface,File Descriptor,我似乎在任何地方都找不到答案,我试图在Java中获得一个套接字,并交出它的文件描述符编号,以便在C二进制文件中使用它(fd将作为参数) 我已使用反射获取文件描述符。。。但在任何地方都无法访问实际数字 我知道其他人也建议使用JNI,但如果可能的话,我想把它保留在Java中(并且不能完全弄清楚怎么做)在Java 7中,您可以将SocketInputStream强制转换为FileInputStream,然后调用getFD()来获取FileDescriptor对象 然后可以使用反射访问FileDescr

我似乎在任何地方都找不到答案,我试图在Java中获得一个套接字,并交出它的文件描述符编号,以便在C二进制文件中使用它(fd将作为参数)

我已使用反射获取文件描述符。。。但在任何地方都无法访问实际数字


我知道其他人也建议使用JNI,但如果可能的话,我想把它保留在Java中(并且不能完全弄清楚怎么做)

在Java 7中,您可以将
SocketInputStream
强制转换为
FileInputStream
,然后调用
getFD()
来获取
FileDescriptor
对象

然后可以使用反射访问FileDescriptor对象的
private int fd
字段。(使用
Class.getDeclaredField(…)
方法获取字段,调用
Field.setAccessible(true)
,然后使用
Field.getInt(…)
获取字段值)



请注意,这样做可能会使您的代码平台依赖于此。无法保证特定的私有字段将出现在较旧的。。。或者Java的新版本,或者其他供应商/供应商的Java实现。

Stephen C的回答解决了如何获取
文件描述符的问题,但这里有一个从该对象获取文件描述符编号的方法。在Windows上,
FileDescriptor
在内部使用
long handle
而不是
int fd
,因此此方法首先检查是否使用了
handle
,如果是,则返回,否则返回
fd
。我没有像OP使用的那样用套接字测试这个问题,但是我想
Windows
jvm仍然使用
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;
}

这对手术没什么帮助。。。不管怎么说,好吧,这不会暴露底层套接字fd。@Nim-你必须问他。。。但这是我的意图。在你宣布它行不通之前,你看过源代码了吗?(提示:我有过。)这正是我想要的,我已经有了FileDescriptor对象,我只需要fd字段,但我正在查看API的一个非定制版本(必须是),因为它没有显示任何私有int fd字段。。。这是本机文件描述符,对吗?如果是,那么塔汉克斯@user1018513-您必须查看源代码。它是一个私有字段,在JavaSE javadocs中没有显示私有字段。我看了Java7版本。。。这在其他版本中可能有所不同。我有一个刚从ServerSocketChannel返回的套接字对象#Socket()#accept()。当我对其调用getInputStream()并尝试将其转换为FileInputStream时,我得到了一个不能转换SocketAdaptor的ClassCastException:sun.nio.ch.SocketAdaptor$SocketInputStream不能转换为java.io.FileInputStream“好吧,你不能,即使你可以,我也看不出你怎么能”将它交给“其他二进制文件?也许如果你发布了你真正想要做的事情,可能会有一些替代方案?我可以,只是这样做了,它就像一个符咒:)将描述符编号传递给另一个进程通常是没有意义的-另一个进程中的相同编号不一定指同一件事。您的系统上有多少进程正在为标准输出使用文件描述符
1
stdout
对它们都一样吗?我的印象是调用Exec方法(Java运行时)创建了一个子进程,而不是一个完全独立的进程,这意味着文件描述符将被共享。如果不是这样的话,那么我将不得不使用JNI和dup系统调用。看起来它做了类似于
fork()
/
exec()
(它从父级继承描述符的副本)的事情,但也关闭了子级中的
stdin
stdout
stderr
之外的所有内容。