您的位置:首页 > 编程语言 > C语言/C++

JNI使用实例之C、C++ DLL回调java成员函数

2016-07-12 11:30 781 查看

使用场景描述如下:

1、使用java程序调用C开发的DLL,传入一个已封装的socket对象

2、在C开发的DLL中根据传入的对象调用java提供的recv()、send()函数发送数据

java部分对应的代码如下:

// ISocketBase.java
package com.tms;
public interface ISocketBase {
public void send(byte [] data);
public byte [] recv(int timeout);
}
// SocketImp.java
package com.tms;

import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.charset.*;

public class SocketImp implements  ISocketBase{
private ServerSocket server;
private Socket socket;

private OutputStream dos;
private InputStream dis;

public SocketImp() {
}

public void EndSocket() {
try {
dis.close();
dos.close();
socket.close();
server.close();
} catch (IOException e) {
}
}

public void StartSocket() {
try {
server = new ServerSocket(8888);
System.out.println("start server connetion, port = 8888.");
socket = server.accept();

dos = socket.getOutputStream();
dis = socket.getInputStream();
} catch (SocketException e) {
System.out.println("The network connection is exception, the program exits.");
} catch (IOException e) {
e.printStackTrace();
}
}

private static void printHexString(byte[] b, int iLen)
{
for (int i = 0; i < iLen; i++)
{
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1)
{
hex = '0' + hex;
}
System.out.print(hex.toUpperCase() + " ");
}
System.out.println("");
}

@Override
public void send(byte[] bytes) {
try {
dos.write(bytes);
System.out.println("[java send] length = " + bytes.length + ".");
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public byte[] recv(int timeout) {
byte[] cRecvData = new byte[1024 * 3];
int iLength = 0;

try {
socket.setSoTimeout(timeout);
iLength = dis.read(cRecvData);
printHexString(cRecvData, iLength);
System.out.println("java read length: " + iLength);
} catch (Exception e) {
e.printStackTrace();
}

byte[] cRet = new byte[iLength];
for(int i = 0; i < iLength; ++i) {
cRet[i] = cRecvData[i];
}
return cRet;
}
}
// CallDllNative.java
package com.tms;

import java.io.*;

public class CallDllNative {

static{
System.loadLibrary("C_DLL_NAME");
}

public native static void Download(ISocketBase socketBase, String binFile, StringBuffer retCode);

public static void main(String args[]) {
String binFile = new String("./123.txt");
SocketImp socket;
StringBuffer retCode = new StringBuffer("23");

socket = new SocketImp();
socket.StartSocket();

System.out.println("CallDllNative is running... ...");
try
{
Download(socket, binFile, retCode);
} catch (Exception e) {
e.printStackTrace();
}

System.out.println("retCode = " + retCode);

socket.EndSocket();
}
}


c部分对应的代码如下:

// Download.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_tms_CallDllNative */

#ifndef _Included_com_tms_CallDllNative
#define _Included_com_tms_CallDllNative

extern int SendData(char* pSendData, int iSendDataLen);
extern int RecvData(char* pRecvData, int iRecvDataLen, int timeout);

#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     com_tms_CallDllNative
* Method:    Download
* Signature: (Lcom/tms/ISocketBase;Ljava/lang/String;Ljava/lang/StringBuffer;)V
*/
JNIEXPORT void JNICALL Java_com_tms_CallDllNative_Download
(JNIEnv *, jclass, jobject, jstring, jobject);

#ifdef __cplusplus
}
#endif
#endif


// Download.c
#include <stdio.h>
#include <string.h>

#include "Download.h"

static JNIEnv*        s_env;
static jobject        s_socketBase;
static jclass        s_clsSocket;

extern int Download(const char* pFilePath);

int SendData(char* pSendData, int iSendDataLen)
{
    jmethodID sendFun = (*s_env)->GetMethodID(s_env, s_clsSocket, "send", "([B)V");
    jbyteArray pSend = (*s_env)->NewByteArray(s_env, iSendDataLen);

    if(NULL == sendFun || NULL == pSend) {
        printf("NULL == sendFun || NULL == pSend.\n");
        return -1;    // OutOfMemoryError already thrown
    }
    
    (*s_env)->SetByteArrayRegion(s_env, pSend, 0, iSendDataLen, (jbyte*)pSendData);
    
    (*s_env)->CallVoidMethod(s_env, s_socketBase, sendFun, pSend);
    
    (*s_env)->ReleaseByteArrayElements(s_env, pSend, (*s_env)->GetByteArrayElements(s_env, pSend, NULL), 0);

    return iSendDataLen;
}

int RecvData(char* pRecvData, int iRecvDataLen, int timeout)
{
    jbyteArray  jRecvArray;
    jbyte*      jRecv;
    int         iRecvLen;
    jmethodID   recvFun = (*s_env)->GetMethodID(s_env, s_clsSocket, "recv", "(I)[B");

    jRecvArray = (jbyteArray)(*s_env)->CallObjectMethod(s_env, s_socketBase, recvFun, timeout);
    if(NULL == jRecvArray) {
        printf("NULL == jRecvArray.\n");
        return -1;
    }
    
    jRecv = (*s_env)->GetByteArrayElements(s_env, jRecvArray, 0);
    if(NULL == jRecv) {
        printf("NULL == jRecv.\n");
        return -1;
    }
    iRecvLen = (*s_env)->GetArrayLength(s_env, jRecvArray);
    if(iRecvLen > iRecvDataLen) {
        iRecvLen = iRecvDataLen;
    }
    memcpy(pRecvData, jRecv, iRecvLen);
    (*s_env)->ReleaseByteArrayElements(s_env, jRecvArray, jRecv, 0);

    return iRecvLen;
}

static int SetRetValue(int iRetValue, jobject retCode)
{
    char      cRetCode[20];
    int       iLen = 0;
    jstring   strRetCode;

    jclass    clsRetCode    = (*s_env)->GetObjectClass(s_env, retCode);
    jmethodID lenFunID    = (*s_env)->GetMethodID(s_env, clsRetCode, "length", "()I");
    jmethodID deleteFunID    = (*s_env)->GetMethodID(s_env, clsRetCode, "delete", "(II)Ljava/lang/StringBuffer;");
    jmethodID appendFunID    = (*s_env)->GetMethodID(s_env, clsRetCode, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");

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

    if(iRetValue < 0)
    {
        iRetValue = -iRetValue;
    }

    cRetCode[0] = iRetValue / 10 + '0';
    cRetCode[1] = iRetValue % 10 + '0';
    cRetCode[2] = '\0';
    strRetCode    = (*s_env)->NewStringUTF(s_env, cRetCode);

    if(NULL == clsRetCode || NULL == lenFunID || NULL == deleteFunID
        || NULL == appendFunID || NULL == strRetCode) {
        printf("SetRetValue == NULL.\n");
        return -1;
    }

    iLen = (*s_env)->CallIntMethod(s_env, retCode, lenFunID);
    (*s_env)->CallObjectMethod(s_env, retCode, deleteFunID, 0, iLen);
    (*s_env)->CallObjectMethod(s_env, retCode, appendFunID, strRetCode);

    (*s_env)->DeleteLocalRef(s_env, strRetCode);

    return 0;
}

/*
 * Class:     com_tms_DownloadNative
 * Method:    tmsDownload
 * Signature: (Lcom/tms/ISocketBase;Ljava/lang/String;Ljava/lang/StringBuffer;)V
 */
JNIEXPORT
bed7
void JNICALL Java_com_tms_CallDllNative_Download
  (JNIEnv* env, jclass cls, jobject socketBase, jstring binFile, jobject retCode)
{
    int iRet = 0;
    const char *pFilePath = (*env)->GetStringUTFChars(env, binFile, NULL);
    
    s_clsSocket = (*env)->GetObjectClass(env, socketBase);
    if(NULL == pFilePath || NULL == s_clsSocket) {
        printf("NULL == pFilePath || NULL == s_clsSocket.\n");
        return ;
    }
    
    s_env = env;
    s_socketBase = socketBase;
    
    iRet = Download(pFilePath);
    
    if(0 != SetRetValue(iRet, retCode)) {
        printf("Failed to SetRetValue().\n");
        return ;
    }
    
    (*env)->ReleaseStringUTFChars(env, binFile, pFilePath);
}

对应的java编译命令如下:

javac -d . com\tms\*.java

java -Djava.library.path=. com.tms.CallDllNative 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JNI DLL java 回调