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