java学习笔记
依旧是参考:
1
| https://www.javasec.org/javase/JNI/
|
只不过版本有点老,会报一些错误,还是建议自己再修改代码
URLConnection
在java中,Java抽象出来了一个URLConnection类,它用来表示应用程序以及与URL建立通信连接的所有类的超类,通过URL类中的openConnection方法获取到URLConnection的类对象。
URLConnection:是所有与 URL 建立通信的类的父类。具体的协议支持类(如 HTTP、FTP 等)会继承 URLConnection。
使用URL发起一个简单的请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package org.example; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection;
public class Main{ public static void main(String[] args)throws Exception{ URL url=new URL("http://www.baidu.com"); URLConnection connection=url.openConnection(); connection.setRequestProperty("user-agent","shallot"); connection.setConnectTimeout(1000); connection.connect(); connection.getHeaderFields(); connection.getInputStream(); StringBuilder reponse=new StringBuilder(); BufferedReader in=new BufferedReader( new InputStreamReader(connection.getInputStream()) ); String line; while((line=in.readLine())!=null){ reponse.append("/n").append(line); } System.out.println(reponse.toString()); } }
|
请求成功

JNI安全基础
JNI (Java Native Interface,JAVA 本地接口) 允许 Java 代码和其它编程语言编写的代码进行交互,主要为Java和Native层(C/C++)相互调用的接口规范,但是并不妨碍扩展其他语言。
感觉在学习的过程中已经遇到了很多次了看见了还是有点陌生,感觉自己是鱼的记忆哈哈(
JNI-定义native方法
首先在java中如果想要调用native方法需要现在类中定义一个native方法。

我们需要使用native关键字定义一个类似于接口的方法
JNI-生成类头文件
现在我们需要编译并生成c语言头文件

org_example_Test.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <jni.h>
#ifndef _Included_org_example_Test #define _Included_org_example_Test #ifdef __cplusplus extern "C" { #endif
JNIEXPORT jstring JNICALL Java_org_example_Test_exec (JNIEnv *, jclass, jstring);
#ifdef __cplusplus } #endif #endif
|
头文件命名强制性
javac生成的头文件名的函数命名方式具有非常强制性的约束方式的:比如Java_org_example_Test_exec中的Java_是固定的前缀缀,org_example_Test_exec是类名,exec是函数名。
(JNIEnv *, jclass, jstring)表示分别是JNI环境变量对象、java调用的类对象、参数入参类型。
JNI-基础数据类型
需要特别注意的是Java和JNI定义的类型是需要转换的,不能直接使用Java里的类型,也不能直接将JNI、C/C++的类型直接返回给Java

留个档,虽然用到的时候还是会查吧(
jstring转char*:env->GetStringUTFChars(str, &jsCopy)
char*转jstring: env->NewStringUTF(“Hello…”)
字符串资源释放: env->ReleaseStringUTFChars(javaString, p);
JNI-编写C/C++本地命令执行实现
写好了头文件之后,我们使用c语言来编写函数的最终实现方式。
Test.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include "org_example_Test.h" #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
JNIEXPORT jstring JNICALL Java_org_example_Test_exec (JNIEnv *env, jclass clazz, jstring command) {
if (command != NULL) { const char *cmd = (*env)->GetStringUTFChars(env, command, NULL); if (cmd == NULL) { return NULL; }
FILE *fp = popen(cmd, "r"); if (fp == NULL) { (*env)->ReleaseStringUTFChars(env, command, cmd); return NULL; }
char buffer[128]; char *result = NULL; size_t result_len = 0;
while (fgets(buffer, sizeof(buffer), fp) != NULL) { size_t chunk_len = strlen(buffer); char *temp = realloc(result, result_len + chunk_len + 1); if (temp == NULL) { free(result); pclose(fp); (*env)->ReleaseStringUTFChars(env, command, cmd); return NULL; } result = temp; memcpy(result + result_len, buffer, chunk_len); result_len += chunk_len; result[result_len] = '\0'; }
pclose(fp); (*env)->ReleaseStringUTFChars(env, command, cmd);
if (result != NULL) { jstring jResult = (*env)->NewStringUTF(env, result); free(result); return jResult; } }
return NULL; }
|
编译命令:
1
| gcc -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -shared -o libtest.jnilib org/example/Test.c
|
test1.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package org.example;
import java.io.File;
public class Test1 { public static void main(String[] args) { String cmd = "whoami"; try { File libPath = new File("libtest.jnilib"); System.load(libPath.getAbsolutePath()); Class<?> cls = Class.forName("org.example.Test"); String result = (String) cls.getMethod("exec", String.class).invoke(null, cmd); System.out.println("命令执行结果:\n" + result); } catch (Exception e) { e.printStackTrace(); } } }
|
运行结果:

做完了一系列操作来探究一下这些操作在干什么?
实际上使用 Java 编写一个 exec(String cmd) 方法,通过 JNI 技术调用 C 语言实现,执行系统命令,并把输出结果返回到 Java。
第一步:定义 Java 接口类(Test.java)
第二步:生成 JNI 头文件
第三步:用 C 实现命令执行逻辑(Test.c)
第四步:将 Test.c 编译为动态链接库(.so/.jnilib)
第五步:写 Java 测试类调用这个 native 方法(Test1.java)