因为需要接入统一的安全服务,调用验证码接口,对方是使用UDP协议进行通信,并且不提供http service调用接口,没有提供客户端包,丢了一个C的协议和client包过来,本想用java socket来自己实现协议,但是协议甚至麻烦,一看就想死,无奈考虑JNI调用实现。
JAVA的定义的接口如下:
public class VerifyCoder { static { try { System.loadLibrary("vc"); } catch (Exception e) { e.printStackTrace(); } } public native ImageCode getCoderImage(Service[] services,int timeout,int appid,String clientIP,long uin,int type,String filename); public native ImageCode getCoderBytes(Service[] services,int timeout,int appid,String clientIP,long uin,int type); public native int vefiryCoder(Service[] services,int timeout,int appid,String clientIP,String code,String sig); }
public native ImageCode getCoderImage(Service[] services,int timeout,int appid,String clientIP,long uin,int type,String filename);可用于指定文件存储参数,用于生成验证码图片,返回图片绝对路径。理论上该filename可以实用sessionid作为临时名称,或者考虑实用tmpnam生成。
public native ImageCode getCoderBytes(Service[] services,int timeout,int appid,String clientIP,long uin,int type);可用于获取验证码的二进制数据数组。
public native int vefiryCoder(Service[] services,int timeout,int appid,String clientIP,String code,String sig);主要是用签名和用户填写的验验证码进行校验,返回标志位。
#include <jni.h> /* Header for class com_corey_verifycode_VerifyCoder */ #ifndef _Included_com_corey_verifycode_VerifyCoder #define _Included_com_corey_verifycode_VerifyCoder #ifdef __cplusplus extern "C" { #endif /* * Class: com_qq_verifycode_VerifyCoder * Method: getCoderImage * Signature: ([Lcom/qq/verifycode/Service;IILjava/lang/String;JILjava/lang/String;)Lcom/qq/verifycode/ImageCode; */ JNIEXPORT jobject JNICALL Java_com_qq_verifycode_VerifyCoder_getCoderImage (JNIEnv *, jobject, jobjectArray, jint, jint, jstring, jlong, jint, jstring); /* * Class: com_qq_verifycode_VerifyCoder * Method: getCoderBytes * Signature: ([Lcom/corey/verifycode/Service;IILjava/lang/String;JI)Lcom/qq/verifycode/ImageCode; */ JNIEXPORT jobject JNICALL Java_com_qq_verifycode_VerifyCoder_getCoderBytes (JNIEnv *, jobject, jobjectArray, jint, jint, jstring, jlong, jint); /* * Class: com_qq_verifycode_VerifyCoder * Method: vefiryCoder * Signature: ([Lcom/corey/verifycode/Service;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_corey_verifycode_VerifyCoder_vefiryCoder (JNIEnv *, jobject, jobjectArray, jint, jint, jstring, jstring, jstring); #ifdef __cplusplus } #endif #endif
jsize serviceLength=(env)->GetArrayLength(services); stInit.iSvrNum = serviceLength; for(int i=0;i<serviceLength;i++){ jobject service=(env)->GetObjectArrayElement(services,i); jclass serviceClass=(env)->FindClass("com/qq/verifycode/Service"); jfieldID ipFieldID=(env)->GetFieldID(serviceClass,"ip","Ljava/lang/String;"); jfieldID portFieldID=(env)->GetFieldID(serviceClass,"port","I"); jint port=(env)->GetIntField(service,portFieldID); stInit.stRemoteSvr[i].usSvrPort = port; jstring jip=(jstring)(env)->GetObjectField(service,ipFieldID); char* ip=(char*)(env)->GetStringUTFChars(jip,NULL); strncpy(stInit.stRemoteSvr[i].aszIp, ip, sizeof(stInit.stRemoteSvr[i].aszIp) - 1); env->ReleaseStringUTFChars(jip,ip); }
java对象的构建:
jclass imageCodeClass=(env)->FindClass("com/qq/verifycode/ImageCode"); jfieldID imagePathFieldID=(env)->GetFieldID(imageCodeClass,"imagePath","Ljava/lang/String;"); jfieldID sigFieldID=(env)->GetFieldID(imageCodeClass,"sig","Ljava/lang/String;"); jmethodID construction_id=(env)->GetMethodID(imageCodeClass,"<init>","()V"); jobject imageCode = (env)->NewObject(imageCodeClass, construction_id);
env->SetObjectField(imageCode,imagePathFieldID,(env)->NewStringUTF("")); env->SetObjectField(imageCode,sigFieldID,(env)->NewStringUTF("getCaptcha error"));
char * clientIP =(char*)env->GetStringUTFChars(jclientIP,NULL); env->ReleaseStringUTFChars(jclientIP,clientIP);
char* data=(char*)stOut.aucPicBuffer; jbyteArray bytes=0; bytes=(env)->NewByteArray(stOut.usPicData); if(bytes!=NULL){ (env)->SetByteArrayRegion(bytes,0,stOut.usPicData,(jbyte*)data); }