Java与c语言sosket通信,JNI系列入门之C语言与Java的双向通信(二)

JNI系列文章:

Jerry哥人狠话不多,直接讲正题。

C层向Java层通信

C层访问Java层的方法

// java代码

/*

* 在C中调用次方法,获取登入的用户id

*/

private String getLoginUserId(){

return "100010";

}

复制代码// c代码

// 3. 访问java方法

JNIEXPORT void JNICALL Java_com_jerry_jnitest_JniTest_accessMethod

(JNIEnv *env, jobject jobj){

// 获取jclass

jclass cls = (*env)->GetObjectClass(env, jobj);

// 获取调用方法的jmethodID

jmethodID methodID = (*env)->GetMethodID(env, cls, "getLoginUserId", "()Ljava/lang/String;");

// 调用获取登录用户id的方法

jint value = (*env)->CallIntMethod(env, jobj, methodID);

printf("userId = %s\n", value);

}

复制代码C层访问Java层的静态方法

// java代码

// c中调用的java静态方法

/**

* 获取文件的大小

* @param pathName

* @return 文件大小

*/

public static long getFileSize(String pathName){

return new File(pathName).length();

}

复制代码// 创建和写入一个字符串到文件中,并返回文件大小

JNIEXPORT jlong JNICALL Java_com_jerry_jnitest_JniTest_createAndWriteFile

(JNIEnv *env, jobject jobj, jstring jstr_file_path){

// 写入的文件路径 jstring->c

char *filename = (*env)->GetStringUTFChars(env, jstr_file_path, NULL);

printf("filename: %s\n", filename);

// 创建一个文件, "w"表示写入权限,文件存在则覆盖

FILE *fp = fopen(filename, "w");

char *text = "在C中创建一个文件并写入内容,并返回文件大小";

// c的文件io函数,写入文件

fputs(text, fp);

// 关闭流

fclose(fp);

// 计算文件的长度,这里不用c的函数来计算,改用调用java的文件api的方式来计算

// 获取getFileSize方法所在类的类类型

jclass jcls = (*env)->GetObjectClass(env, jobj);

// 获取方法的id

jmethodID mid = (*env)->GetStaticMethodID(env, jcls, "getFileSize",

"(Ljava/lang/String;)J");

// 调用方法

jlong file_size = (*env)->CallStaticLongMethod(env, jcls, mid, jstr_file_path);

printf("file_size: %lld", file_size);

// 释放filename

(*env)->ReleaseStringUTFChars(env, jstr_file_path, filename);

return file_size;

}

复制代码

这里我通过C调用了java的文件计算api,因为java计算文件比较简单,直接File.length()就好了。当然也可以用c来实现获取文件的长度大小:

// 4. 获取文件大小

int filesize(FILE *fp){

int length = 0;

if (fp == NULL) {

return length;

}

// 将文件指针的位置,重新定位文件指针

// 0是偏移量,SEEK_END表示文件的末尾位置

fseek(fp, 0, SEEK_END);

// 返回当前文件指针,相对于文件开头的位置偏移量,就是文件字节长度

length = ftell(fp);

printf("length = %d\n", length);

return length;

}

复制代码

小伙伴们肯定会有疑问,你这方法的签名,记不住啊,容易懵逼啊。没有关系,我们还可以用命令的方式生成:c5c0347e8bf8d61501d8f8f4f1f76f06.png

javap -s -p 类的完整名称,可以自动生成属性和方法签名。

C层访问Java层的构造方法,并创建Java对象返回

// 5. 访问java的构造方法

// 使用java.util.Date获得一个时间戳

JNIEXPORT jobject JNICALL Java_com_jerry_jnitest_JniTest_accessConstructor

(JNIEnv *env, jobject jobj){

// 获取jclass

jclass cls = (*env)->FindClass(env, "java/util/Date");

// 获取jmethodID, 构造方法的名字使用

jmethodID contructor_mid = (*env)->GetMethodID(env, cls, "", "()V");

// 调用构造方法,实例化一个Date对象

jobject date_jobj = (*env)->NewObject(env, cls, contructor_mid);

// 调用Date的getTime方法

// 获取date的jclass

jclass date_cls = (*env)->GetObjectClass(env, date_jobj);

// 获取getTime的jmethodID

jmethodID getTime_mid = (*env)->GetMethodID(env, date_cls, "getTime", "()J");

// 调用getTime方法

jlong timestamp_jlong = (*env)->CallLongMethod(env, date_jobj, getTime_mid);

printf("timestamp = %lld\n", timestamp_jlong);

return date_jobj;

}

复制代码

构造方法比较特殊,在获取jmethodID的时候传入的方法名是固定的。

java中传入数组

// 8. java传入一个数组进行排序后同步

// 比较两个数的大小

int compare(int *a, int *b){

return (*a) - (*b);

}

JNIEXPORT void JNICALL Java_com_jerry_jnitest_JniTest_inputSortArray

(JNIEnv *env, jobject jobj, jintArray jintArr){

// 获取数组中的元素jint*

jint *int_arr = (*env)->GetIntArrayElements(env, jintArr, NULL);

// 获取数组长度

int length = (*env)->GetArrayLength(env, jintArr);

// 利用快速排序法排列数组

qsort(int_arr, length, sizeof(jint), compare);

// 同步操作后的数组内存到java中

// 最后一个参数mode的解释

// 0:Java的数组更新同步,然后释放C/C++的数组内存

// JNI_ABORT:Java的数组不会更新同步,但是释放C/C++的数组内存

// JNI_COMMIT:Java的数组更新同步,不释放C/C++的数组内存(但是函数执行完了局部的变量还是会释放掉)

(*env)->ReleaseIntArrayElements(env, jintArr, int_arr, 0);

}

复制代码

ReleaseIntArrayElements这个函数很重要,只有调用了这个函数,C中操作的数组元素,才会同步到java,否则java中传入的数组打印后还是原来的。

C中生成一个数组返回给java

// 9. C中生成一个数组返回给java

JNIEXPORT jintArray JNICALL Java_com_jerry_jnitest_JniTest_outputArray

(JNIEnv *env, jobject jobj, jint len){

// 创建一个jintArray数组变量

jintArray jint_Arr = (*env)->NewIntArray(env, len);

// 将jintArray转换成c的jint*指针进行数组赋值

jint *elements = (*env)->GetIntArrayElements(env, jint_Arr, NULL);

int i = 0;

for (; i < len; i++) {

elements[i] = i;

}

// 将C中的创建修改的数组同步到Java中

(*env)->ReleaseIntArrayElements(env, jint_Arr, elements, 0);

return jint_Arr;

}

复制代码

同样也要调用ReleaseIntArrayElements函数,去同步操作的数据,java获取的数组才会有值,同时释放掉C/C++的数组内存。

JNI系列文章:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值