Linux下JAVA程序调用so库的接口函数实例(JNA)
目录
前言
JNI调用过程
JNA调用过程
Linux下通过JNA技术实现JAVA程序调用so库函数的实例。
4.1 开发环境
4.2 so库的生成
4.2.1 编写文件 sayhello.h
4.2.2 编写文件 sayhello.c
4.2.3 编写编译命令文件 64cmd.sh和32cmd.sh
4.2.4 编译生成so库
4.3 JNA程序的编写
4.3.1 编写实例化so库的接口文件 Clibrary.java
4.3.2 编写C接口函数调用方法 JNATest.java
4.4 执行JAVA程序
- 总结
1. 前言
最近研究了一下Linux下java程序调用C语言so库接口函数的相关知识,在网上也找了一些资料,然后简单的做了一些开发验证,特别在此处做一总结,不过,在讲解代码之前,需先向读者简单介绍下JNI与JNA的渊源,篇幅不会太多,废话不多说,开始。
2. JNI调用过程
JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。JNI调用过程大致如下:
从上面可以看出,使用JNI技术调用so库,步骤有些麻烦,不仅要懂JAVA编程,而且要懂C编程。
3. JNA调用过程
JNA(Java Native Access )提供一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。个人理解JNA是针对JNI的进一步优化。
从上面可以看出,使用JNA技术调用so库,步骤相比JNI来说简化了许多,在这里只需要一个JNA的jar包和懂得JAVA的编程知识即可,接下来就开始实战吧!
4. Linux下通过JNA技术实现JAVA程序调用so库函数的实例。
事先声明,因为java程序需要一个so库来进行调用,我在网上也没找到一个合适的so库,所以就参考网上的资料编写了一个,接下来会先介绍so库的生成,再介绍JNA代码的调用,下图是代码结构:
4.1 开发环境
Linux系统:Linux localhost.localdomain 2.6.32-642.el6.x86_64 redhat
jdk版本:java version “1.8.0_191” 64-Bit
JNA的jar包版本:jna-4.2.1.jar
4.2 so库的生成
4.2.1 编写文件 sayhello.h
创建c_code目录,编写头文件代码:
#include <stdio.h>
#include <string.h>
int sayHello();
int add(int a, int b);
char* outputString(char* str);
该头文件声明了3个函数,具体实现参考4.2.2中的sayhello.c。
4.2.2 编写文件 sayhello.c
在c_code目录中,编写.c文件代码:
#include "sayhello.h"
/**
* 打印 Hello World!
*/
int sayHello()
{
printf("Hello World!\n");
return 1;
}
/**
* 返回整型类型,两数相加的结果
*/
int add(int a, int b)
{
return a + b;
}
/**
* 返回字符串类型,输出特定字符串+用户输入的数据
*/
char* outputString(char* str)
{
char* strTmp[128] = {0};
strcpy(strTmp, "your input String is :");
strcat(strTmp, str);
return strTmp;
}
该.c文件编写了3个函数,实现的功能分别是直接打印“Hello World!”、java传入两数并在c中相加返回int型结果、输出字符串型结果(特定字符串+java程序传入字符串)。
4.2.3 编写编译命令文件 64cmd.sh和32cmd.sh
在c_code目录中,编写编译命令文件64cmd.sh和32cmd.sh。
64cmd.sh代码如下:
gcc -m64 -fPIC -c ./*.c -I./
gcc -m64 -shared -o libsayhello.so *.o
rm *.o
cp libsayhello.so ../java_code/
32cmd.sh代码如下:
gcc -m32 -fPIC -c ./*.c -I./
gcc -m32 -shared -o libsayhello.so *.o
rm *.o
cp libsayhello.so ../java_code/
对比下64cmd.sh和32cmd.sh两个文件代码,不难看出,区别仅在于gcc命令后面的gcc -m64与gcc -m32。gcc -m64的意思是编译64位程序,gcc -m32的意思是编译32位程序(注意:gcc -m64仅用于64位的Linux机器)。
以64cmd.sh命令文件为例:
第1行命令:编译.c文件,输出.o文件
第2行命令:输出so库
第3行命令:删除.o文件
第4行命令:将生成的so库拷贝至java_code目录下,以便java程序调用。
4.2.4 编译生成so库
执行命令“sh 64cmd.sh”生成so库——libsayhello.so(可能会报没有权限的错误,那么需要执行命令“chmod +x 64cmd.sh”为文件赋予可执行权限)。
4.3 JNA程序的编写
4.3.1 编写实例化so库的接口文件 Clibrary.java
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface Clibrary extends Library{
Clibrary INSTANCE = (Clibrary) Native.loadLibrary("sayhello", Clibrary.class);
int sayHello();
int add(int a, int b);
String outputString(String str);
}
解析:
“Clibrary INSTANCE = (Clibrary) Native.loadLibrary(“sayhello”, Clibrary.class);”就是实例化so库到一个对象里面,其中sayhello参数代表的是“libsayhello.so”,在JNA中会默认去掉lib前缀,和.so后缀。
接下来的代码是3个方法的声明,注意,方法的名字要与C代码中的函数名称保持一致。
另附一张JNA与C数据类型的对应关系表:
JNA与C数据类型对应关系表Native Type | Size | Java Type | Common Windows Types |
char | 8-bit integer | byte | BYTE, TCHAR |
short | 16-bit integer | short | WORD |
wchar_t | 16/32-bit character | char | TCHAR |
int | 32-bit integer | int | DWORD |
int | boolean value | boolean | BOOL |
long | 32/64-bit integer | NativeLong | LONG |
long long | 64-bit integer | long | __int64 |
float | 32-bit FP | float | |
double | 64-bit FP | double | |
char | C string | String | LPTCSTR |
void | pointer | Pointer | LPVOID, HANDLE, LPXXX |
4.3.2 编写C接口函数调用方法 JNATest.java
public class JNATest {
public static void main(String[] args) {
int result = Clibrary.INSTANCE.sayHello();
int a = 2;
int b = 3;
System.out.println(a+"+"+b+"="+Clibrary.INSTANCE.add(2, 3));
System.out.println(Clibrary.INSTANCE.outputString("Hello JNA!"));
}
}
4.4 执行JAVA程序
至此,Linux下JAVA程序调用so库的接口函数实例编写完成并执行成功。
5. 总结
本篇先是讲解了JNI与JNA的调用过程,下来就是Linux下JAVA程序调用so库的接口函数实例的编写与执行,共实现了3个不同返回值函数的调用。通篇文字不多,但是感觉篇幅有些长,毕竟加了代码及解析,希望对各位读者有用,我自己也保留一份以备查阅。最后,谢谢各位读者的耐心阅读,如有语句不通顺或者不准确的地方,还请指正!谢谢!(^__^)
程序源码:https://download.csdn.net/download/sinat_31511255/11006576,(上传时,没有积分的定义,不知道怎么修改,默认5分了-_-||,如果有人知道怎么修改,麻烦告知一下,谢谢!)
参考链接:
JNA数据类型的对应以及使用
JNA实战笔记汇总<一> 简单认识JNA|成功调用JNA
百度百科:JNI
百度百科:JNA
最后,谢谢各位读者的耐心阅读,如有语句不通顺或者不准确的地方,大家也可以提提改善的意见!谢谢!(^__^)
还没有评论,来说两句吧...