【问题标题】:Wrapping BSD select() with JNA用 JNA 包装 BSD select()
【发布时间】:2010-11-21 06:11:27
【问题描述】:

我需要使用 JNA 将类似 BSD 的 C 套接字 API 包装到 Java。它与标准 BSD 套接字 API 的功能基本相同。

包装select() 是有问题的,因为它的参数中需要fd_set-结构以及处理fd_sets 所需的FD_* 掩码函数(宏)。我尝试浏览头文件(例如 Ubuntu 8.04 中的 sys/select.h),但定义并不那么简单。尤其是我发现很难找到 FD_*-macros 的实现,这是用 JNA 的 InvocationMapper 包装它们时需要的。

注意:我不是要包装标准的 TCP 或 unix-socket API,而是自定义的。因此,Java 中的内置套接字不符合要求。

【问题讨论】:

    标签: java select jna sockets


    【解决方案1】:

    特别是我发现很难找到FD_*-macros 的实现,这是用 JNA 的 InvocationMapper 包装它们时需要的。

    C 预处理器cpp 有助于了解宏的扩展方式。编写一个使用相关宏的虚拟程序(它应该在词法上是正确的,但不需要编译),通过cpp 运行它并观察会发生什么。

    【讨论】:

      【解决方案2】:

      我为 fd_set 结构使用一个字节数组,并使用一些算法在数组中找到正确的字节位置:

      private static final int FD_SETSIZE = 1024;
      private static final boolean isBigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
      
      private static interface Libc extends Library {
         int select (int nfds, byte[] readfds, byte[] writefds, byte[] errfds, TimeVal timeout);
         //...
         }
      
      private static class FdSet {
         byte[] a;
         FdSet() {
            a = new byte[FD_SETSIZE / 8]; }
         void set (int fd) {
            a[getBytePos(fd)] |= getBitMask(fd); }
         boolean isSet (int fd) {
            return (a[getBytePos(fd)] & getBitMask(fd)) != 0; }
         private static int getBytePos (int fd) {
            if (fd < 0 || fd >= LibcDefs.FD_SETSIZE) {
               throw new RuntimeException("File handle out of range for fd_set."); }
            if (isBigEndian) {
               return (fd / 8 / Native.LONG_SIZE + 1) * Native.LONG_SIZE - 1 -
                     fd / 8 % Native.LONG_SIZE; }
             else {
               return fd / 8; }}
         private static int getBitMask (int fd) {
            return 1 << (fd % 8); }}
      
      private static class TimeVal extends Structure {
         public NativeLong  tv_sec;
         public NativeLong  tv_usec;
         TimeVal (int ms) {
            set(ms); }
         void set (int ms) {
            tv_sec.setValue(ms / 1000);
            tv_usec.setValue(ms % 1000 * 1000); }
         @Override protected List<?> getFieldOrder() {
            return Arrays.asList("tv_sec", "tv_usec"); }}
      
      public boolean waitInputReady (int timeoutMs) throws IOException {
         TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
         FdSet rxSet = new FdSet();
         FdSet errorSet = new FdSet();
         rxSet.set(fileHandle);
         errorSet.set(fileHandle);
         int rc = libc.select(fileHandle + 1, rxSet.a, null, errorSet.a, timeVal);
         checkSelectErrors(rc, errorSet);
         if (rc == 0) {
            return false; }
         if (!rxSet.isSet(fileHandle)) {
            throw new RuntimeException("rxSet bit is not set after select()."); }
         return true; }
      
      public boolean waitOutputReady (int timeoutMs) throws IOException {
         TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
         FdSet txSet = new FdSet();
         FdSet errorSet = new FdSet();
         txSet.set(fileHandle);
         errorSet.set(fileHandle);
         int rc = libc.select(fileHandle + 1, null, txSet.a, errorSet.a, timeVal);
         checkSelectErrors(rc, errorSet);
         if (rc == 0) {
            return false; }
         if (!txSet.isSet(fileHandle)) {
            throw new RuntimeException("txSet bit is not set after select()."); }
         return true; }
      
      private void checkSelectErrors (int rc, FdSet errorSet) throws IOException {
         if (rc == -1) {
            throw new IOException("Error in select(), errno=" + Native.getLastError() + "."); }
         boolean error = errorSet.isSet(fileHandle);
         if (!(rc == 0 && !error || rc == 1 || rc == 2 && error)) {
            throw new RuntimeException("Invalid return code received from select(), rc=" + rc + ", error=" + error + "."); }
         if (error) {
            throw new IOException("Channel error state detected"); }}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多