使用场景描述如下:
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 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