Java 带有JNI的ioctl():断开的文件描述符

Java 带有JNI的ioctl():断开的文件描述符,java,linux,java-native-interface,ioctl,Java,Linux,Java Native Interface,Ioctl,正如这里所解释的,我正在尝试用Java与Linux tun驱动程序接口 但是,因为不能用java调用ioctl(),所以我使用的是java本机接口。只要我不在同一个文件中读写,它就可以正常工作 如果我这样做,我会得到这个异常,我会将其转换为“FileDescriptor处于断开状态”: 以下是java代码: public static void main(String[] arg){ File tunFile = new File("/dev/net/tun");

正如这里所解释的,我正在尝试用Java与Linux tun驱动程序接口

但是,因为不能用java调用ioctl(),所以我使用的是java本机接口。只要我不在同一个文件中读写,它就可以正常工作

如果我这样做,我会得到这个异常,我会将其转换为“FileDescriptor处于断开状态”:

以下是java代码:

public static void main(String[] arg){
        File tunFile = new File("/dev/net/tun");
        FileOutputStream outStream;
        FileInputStream inStream;

        try {

            inStream = new FileInputStream(tunFile);
            outStream = new FileOutputStream(tunFile);
            FileDescriptor fd = inStream.getFD();

            //getting the file descriptor

            Field f = fd.getClass().getDeclaredField("fd");
            f.setAccessible(true);
            int descriptor = f.getInt(fd);


            //use of Java Native Interface
            new TestOuvertureFichier().ioctl(descriptor);

            while(true){
                System.out.println("reading");
                byte[] bytes = new byte[500];
                int l = 0;
                l = inStream.read(bytes);

                //the problem seems to come from here
                outStream.write(bytes,0,l);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
下面是C代码:

JNIEXPORT void JNICALL Java_TestOuvertureFichier_ioctl(JNIEnv *env,jobject obj, jint descriptor){
      struct ifreq ifr;
      memset(&ifr, 0, sizeof(ifr));
      ifr.ifr_flags = IFF_TUN;
      strncpy(ifr.ifr_name, "tun0", IFNAMSIZ);
      int err;

      if ( (err = ioctl(descriptor, TUNSETIFF, (void *) &ifr)) == -1 ) {
          perror("ioctl TUNSETIFF");exit(1);
      }
      return;
}

请注意,
bytes
应至少为接口的MTU大小,例如1500字节。tun fd上的
read()
每次调用时都会准确读取整个数据包


在写入tun设备之前,您应该操作IP报头,尤其是接收到的数据包的源地址和目标地址。

G.Fiedler是正确的,读取的数据应该至少与接口MTU一样大,并且写入的数据不应该超过MTU。除此之外,我还要检查:

  • 在尝试读取或写入之前,接口已启动(ip addr add x.x.x.x/xx dev tun0,ip link set tun0 up)
  • 您只能打开tun设备一次,例如使用。在这里,我不确定流内和流外是否有相同的文件描述符

文件描述符不是通过
new file()
调用创建的,而是在创建
FileInputStream
FileOutputStream
对象时创建的。这意味着您的代码将打开/dev/net/tun文件两次(创建两个不同的文件描述符)

因此,ioctl仅适用于
流内
,而不适用于
流外
。 尝试创建
FileOutputStream
,同时使用与
FileInputStream
相同的文件描述符

outStream = new FileOutputStream(inStream.getFD());    
编辑:FileInputStream可能会打开只读FD。正如JayTE所建议的,最好先创建一个
随机访问文件
,然后使用其中的FD来创建两个流。

新文件输出流(…)
肯定会尝试创建一个新文件。尝试使用一个
RandomAccessFile
而不是两个文件流。
inStream = new FileInputStream(tunFile);
outStream = new FileOutputStream(tunFile);
outStream = new FileOutputStream(inStream.getFD());