JNI与JNA对比

JNI介绍

最开始,java与sdk相互调用,使用的是JNI技术,操作步骤如图


步骤如下:

(A) 用c/c++将已有的sdk进行重新编写(用sun规定的数据结构替代c/c++中的数据结构)
(B) Java中引入第1步中新编写的sdk
(C) 编写java native函数作为链接函数中的代理
(D) 用java调用代理函数

优点:JNI针对sdk是双向调用。sdk可以调用java的API,java可以调用sdk的API

缺点:流程繁琐复杂,需要根据sun公司定义的通用数据结构将源sdk重写一遍(用c/c++),实在头疼

JNA介绍

正是由于JNI操作sdk太复杂,所以sun公司主导开发了JNA框架,其目的就是为了简化:java调用sdk的步骤

步骤如下:

(A) 编写java native函数作为链接函数中的代理
(B) Java调用代理API

优点:简单,省去了根据sun规定的通用数据结构重写sdk的步骤

缺点:单向调用,只有java调用sdk的API,没有sdk调用java的API

JNA运用

加载

windows平台sdk(xxx.dll)加载方法:

public interface MyLibrary extends Library {
   // 不要写扩展名 MylLibrary INSTANCE
= Native.load("xxx", MyLibrary.class); }

linux平台sdk(xxx.so)加载方法:

public interface MyLibrary extends Library {
   // 要写扩展名 MylLibrary INSTANCE
= Native.load("xxx.so", MyLibrary.class); }

类型对应

 

回调函数

sdk代码

void CALLBACK PDCSSTATUS(
          int DCSID,
          int DeviceStatus,
          int DeviceFault, 
          int *pAmpStatus, 
          int ContactInputOpenFault,
          int ContactInputShortFault
);

注意:这里关注【int *pAmpStatus】,这是一个【int指针】,java中用【IntByReference】来做对应。(c/c++中的所有指针类型,JNA中都有对应的xxxByReference与之对应

 

java映射代码

public interface MyLibrary extends Library {

    MylLibrary INSTANCE = Native.load("xxx.so", MyLibrary.class);

   // 与SDK中的方法对应
interface PDCSSTATUS extends Callback { void callback(int dcsID, int deviceStatus, int deviceFault, IntByReference pAmpStatus, int contactInputOpenFault, int contactInputShortFault); } }

 

java调用

public class MyTest {

    // dcs设备信息回调方法
     static MyLibrary.PDCSSTATUS pdcsstatus = (dcsID, deviceStatus, deviceFault, pAmpStatus, contactInputOpenFault, contactInputShortFault) -> {
       log.info("============================================");
       log.info("callback-dcsId:" + dcsID);
       log.info("callback-deviceStatus:" + deviceStatus);
       log.info("callback-deviceFault:" + Integer.toBinaryString(deviceFault));

       // 解析设备状态码
         log.error("callback-pAmpStatus:");
       int[] intArray = pAmpStatus.getPointer().getIntArray(0, 8);
       for (int i = 0; i < intArray.length; i++) {
           log.info("通道" + i + ":" + Integer.toBinaryString(intArray[i]));
       }
    };
}

返回类型为指针,指向数组

sdk代码(其实与上文是同一个函数)

void CALLBACK PDCSSTATUS(
          int DCSID,
          int DeviceStatus,
          int DeviceFault, 
          int *pAmpStatus, 
          int ContactInputOpenFault,
          int ContactInputShortFault
);

参数说明:
pAmpStatus:
    这是一个整数数组,长度为8,对应于8个功放通道的状态和故障。
    每个数组元素的8bits描叙一个功放通道的状态和故障。

    Bit0: 功放通状态(0:未启用,1:正常运行, 2:未正常运行).
    Bit1: 回路故障 (1: 故障, 0: 正常);
    Bit2: 功放是否禁用 (1: 禁用, 0: 未禁用);
    Bit3: 保留
    Bit4: 电源或保护故障(1: 故障, 0: 正常);
    Bit5~Bit7: 保留.

注意:

1. 【int *pAmpStatus】,这是一个【int指针】,java中用【IntByReference】来做对应

2. pAmpStatus参数指向的是一个int[]

 

java映射代码

public interface MyLibrary extends Library {

    MylLibrary INSTANCE = Native.load("xxx.so", MyLibrary.class);

   // 与SDK中的方法对应
     interface PDCSSTATUS extends Callback {
        void callback(int dcsID, int deviceStatus, int deviceFault,
                      IntByReference pAmpStatus, int contactInputOpenFault,
                      int contactInputShortFault);
    }
}

 

java调用

public class MyTest {

    // dcs设备信息回调方法
    static MyLibrary.PDCSSTATUS pdcsstatus = (dcsID, deviceStatus, deviceFault, pAmpStatus, contactInputOpenFault, contactInputShortFault) -> {// 解析设备状态码
         log.error("callback-pAmpStatus:");
       int[] intArray = pAmpStatus.getPointer().getIntArray(0, 8);
       for (int i = 0; i < intArray.length; i++) {
           log.error("通道" + i + ":" + Integer.toBinaryString(intArray[i]));
       }
    };
}

处理指针步骤:

1. 得到指针:getPointer()

2. 根据sdk文档,指针指向的是一个int[8],所以getIntArray(0,8)得到对应的数据

3. 核心代码:int[] intArray = pAmpStatus.getPointer().getIntArray(0, 8);

结构体

本次的sdk中无结构体代码,故没有应用,也就没有研究

问题汇总

sdk无法加载

1. sdk根据不同平台,加载方法不同。上文已经给出了windows平台、linux平台的加载方法

2. sdk版本与系统版本不一致。例如:sdk是32位,而系统是64位

3. sdk依赖库的缺失

  linux可以用:ldd,命令查看

  

   如图:=>右侧没有出现 not found,表示依赖满足

  windows可以用:【dumpbin】进行查看,这里没有做对应的演示

回调函数不执行

java代码定义回调函数时,将其设置为静态变量,防止jvm对其进行回收

 

结束语:感谢各位的耐心阅读。

参考与代码下载

入门

jna项目(主要关注www文件夹下的案例代码)

示例代码下载

posted on 2021-01-18 16:07  安静生活  阅读(604)  评论(0编辑  收藏  举报