java调用JNI总结
工作中需要用到java调用DES加密解密算法进行通信加密、MAC计算等,原来直接有C语言版的DES算法库可以用,但是java用的不熟,java的DES算法库没用过,就想到把C语言的DES算法库编译成DLL,然后通过java的JNI调用。
网上java调用jni的例子挺多,本以为挺简单的,但是实践了一下才知道,好多地方容易出错,这里总结一下容易出错的地方。
java调用JNI,按步骤,首先需要建一个类,声明本地方法。然后用javac编译这个类,最后用javah生成c语言的头文件并实现对应的*.c文件,并编译为动态库。把这个动态库放
在指定位置,如/bin目录下。在java中静态加载这个DLL。
以一个简单的例子说明:
package test;
public class TestDes {
public native void SayHello(String name);
public native void DesOperation(int[] pInOut,int[] pbKey,int cnt);
public native int MathDesMac(int[] pbuf,int len,int[] pbKey,int type);
static
{
System.load(Class.class.getResource("/").getPath()+"test_TestDes.dll");
//System.load("C:/Users/yang/A303workspc/testjni/bin/test/test_TestDes.dll");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("java jni test:");
System.out.println(Class.class.getResource("/").getPath());
//System.out.println(System.getProperty("user.dir"));
TestDes h=new TestDes();
h.SayHello("nice to meet you!rn");
}
}
常见的错误如:java.lang.UnsatisfiedLinkError,
javah -jni -classpath . test.TestDes 错误:无法访问 test.TestDes
javah -jni -classpath . TestDes 错误:无法访问 TestDes 错误的类文件: .TestDes.class 类文件包含错误的类: test.TestDes
原因是有些地方需要注意:
当调用javah命令生成c语言的头文件时,首先需要进入*java的源文件目录下,调用javac 把有本地方法的java类文件编译为*.class,然后用javah命令时,需要在正确的目录下调用,切换回src目录下调用javah -jni命令。注意,指定的类clss文件要带上包名。如 test.TestDes
如在yang@DESKTOP-LRJFD2R ~/a303workspc/testjni/src 目录下,调用javah -jni -classpath . test.TestDes
其中test是包的名字。
生成了test_TestDes.h的头文件。
文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_TestDes */
#ifndef _Included_test_TestDes
#define _Included_test_TestDes
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test_TestDes
* Method: SayHello
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_test_TestDes_SayHello
(JNIEnv *, jobject, jstring);
/*
* Class: test_TestDes
* Method: DesOperation
* Signature: ([I[II)V
*/
JNIEXPORT void JNICALL Java_test_TestDes_DesOperation
(JNIEnv *, jobject, jintArray, jintArray, jint);
/*
* Class: test_TestDes
* Method: MathDesMac
* Signature: ([II[II)I
*/
JNIEXPORT jint JNICALL Java_test_TestDes_MathDesMac
(JNIEnv *, jobject, jintArray, jint, jintArray, jint);
#ifdef __cplusplus
}
#endif
#endif
接下来就需要用GCC把这些头文件中的函数给实现了。为了方便,直接把JNI.h和JNI_md.h文件和需要编译的C文件都放到src目录下。
同时把test_TestDes.h头文件中的include<jni.h>,尖括号换为“JNI.h”
GCC生成动态库,如下:gcc -std=c99 -Wl,--add-stdcall-alias -shared
makefile文件:
######################################## #makefile ######################################## BINARY= test_TestDes CC= gcc LD= ld CFLAGS= -std=c99 -Wl,--add-stdcall-alias #LDSCRIPT= -lws2_32 #LDFLAGS= -Llib #OBJS= helloworld.o OBJS= curcalc_calc.o curcalc_crc.o curcalc_des.o curcalc_md5.o curcalc_oth.o curcalc_sha1.o test_TestDes.o #CFLAGS=-std=c99 .PHONY: clean all:images images: (BINARY).dll(OBJS):%.o:%.c(CC) -c (CFLAGS) < -o (OBJS)(CC) (CFLAGS) -shared -o (BINARY).dll (OBJS)cp (BINARY).dll ../bin clean:rm -f *.o
test_TestDes.c文件如下:
#include "test_TestDes.h"
#include <stdio.h>
#include <string.h>
#include "includes.h"
void JNICALL Java_test_TestDes_SayHello(JNIEnv * env, jobject obj, jstring str)
{
jboolean b ;
char s[80];
memset(s, 0, sizeof(s));
strcpy(s ,(char*)(*env)->GetStringUTFChars(env,str, &b));
printf("Hello, %s", s);
(*env)->ReleaseStringUTFChars(env,str , NULL);
}
void JNICALL Java_test_TestDes_DesOperation(JNIEnv *env, jobject obj, jintArray data, jintArray key, jint t)
{
jboolean b ;
jsize n1,n2;
n1 = (*env)->GetArrayLength(env,data);
n2 = (*env)->GetArrayLength(env,key);
printf("len is %drn",n1);
if((n1 < 8) || (n2 < 8))
{
printf("lenth is not enough!");
return;
}
jint jt1[n1];
jint jt2[n2];
unsigned char buf1[n1];
unsigned char buf2[n2];
//memcpy(s,(jint*)(*env)->GetIntArrayElements(env,data,&b),n);
(*env)->GetIntArrayRegion(env,data,0,n1,jt1);
for(int i=0;i < n1;i++)
{
buf1[i] = jt1[i];
}
printf("jt1 is %d %d %d %drn",jt1[0],jt1[1],jt1[2],jt1[3]);
printf("buf1 is %d %d %d %drn",buf1[0],buf1[1],buf1[2],buf1[3]);
//printf("len is %drn",n2);
//memcpy(s,(jint*)(*env)->GetIntArrayElements(env,data,&b),n);
(*env)->GetIntArrayRegion(env,key,0,n2,jt2);
for(int i=0;i < n2;i++)
{
buf2[i] = jt2[i];
}
CurCalc_DES_DesOperation( buf1, 0,
buf2,
SINGLE_DES_DECRYPTION | ZERO_CBC_IV,
t ) ;
printf("buf1 is %d %d %d %drn",buf1[0],buf1[1],buf1[2],buf1[3]);
(*env)->SetIntArrayRegion(env,data,0,8,jt1);
}
jint JNICALL Java_test_TestDes_MathDesMac(JNIEnv *env, jobject obj, jintArray data, jint len,jintArray key, jint type)
{
return 0;
}
执行结果:
- Spring Cloud第二篇 创建一个Eureka Server
- 数据挖掘实战(一):Kaggle竞赛经典案例剖析
- 华为面试题——单向链表倒转(一次遍历)
- Flask一步步搭建web应用
- (44) 剖析TreeSet / 计算机程序的思维逻辑
- (46) 剖析PriorityQueue / 计算机程序的思维逻辑
- (48) 剖析ArrayDeque / 计算机程序的思维逻辑
- 那些年在win下填过的Django坑
- Python爬虫一步步抓取房产信息
- (47) 堆和PriorityQueue的应用 / 计算机程序的思维逻辑
- 一篇文章完全理解virtualenv
- Python运用蒙特卡洛算法模拟植物生长
- (57) 二进制文件和字节流 / 计算机程序的思维逻辑
- 真正的 Tornado 异步非阻塞
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Linux工具入门:make工具与Makefile文件
- PF_RING的多种负载均衡方法
- 【拓展】686- 如何在 Web 上大规模生成 UUID
- Linux进程管理与性能监控
- 重学数据结构(一、线性表)
- Jmeter系列(49)- 详解 HTTP Cookie 管理器
- java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener问题解决
- ELK + Filebeat + Kafka 分布式日志管理平台搭建
- 一切皆是文件:UNIX,Linux 操作系統的設計哲學
- 【JS】687- 几行代码摸清楚上拉加载原理
- CTO 写的代码,全网被吐槽,真是绝了
- 定义一个函数,在该函数中可以实现任意两个整数的加法。java实现
- JDBC连接ORACLE的三种URL格式
- Centreon+Nagios实战第八篇——Nagios+Centreon添加监控服务
- Centreon+Nagios实战第九篇——利用nrpe插件监控本机