JAvaクライアントとcサービス側通信(JNI+UDP)


このブログはJNI+UDP用
最近、ある研究所とプログラムを調整して、多くの問題に直面して、現在大半を解決して、早くまとめてみましょう.
余談:プログラマーは決して研究所に行かないでください.葬儀場よりも雰囲気が抑圧されているからです.
大まかな需要:
1.ある研究所は、udpアクセスで実行し、udpで結果を返すシミュレーションソフトウェア(C作成)を提供している.伝達パラメータはすべて構造体(C struct)である.
2.java webを利用してウェブサイトを作成し、シミュレーションソフトウェアの呼び出しと結果の表示を実現する.
このニーズを見ると,簡単なudpが実現できると考えられる.しかし、パラメータの伝達は難題になります.
まずjava udp実装を見てみましょう
/**      
 * UDP   .      
 * @author liukang
 */  
public class UdpServerSocket {  
    private byte[] buffer = new byte[1024];  
      
    private DatagramSocket ds = null;  
  
    private DatagramPacket packet = null;  
  
    private InetSocketAddress socketAddress = null;  
  
    private String orgIp;  
  
    /** 
     *     ,       . 
     * @param host    
     * @param port    
     * @throws Exception 
     */  
    public UdpServerSocket(String host, int port) throws Exception {  
        socketAddress = new InetSocketAddress(host, port);  
        ds = new DatagramSocket(socketAddress);  
        System.out.println("     !");  
    }  
      
    public final String getOrgIp() {  
        return orgIp;  
    }  
  
    /** 
     *       ,      bind      . 
     * @param timeout      
     * @throws Exception 
     */  
    public final void setSoTimeout(int timeout) throws Exception {  
        ds.setSoTimeout(timeout);  
    }  
  
    /** 
     *       . 
     * @return       . 
     * @throws Exception 
     */  
    public final int getSoTimeout() throws Exception {  
        return ds.getSoTimeout();  
    }  
  
    /** 
     *          . 
     * @param host   IP 
     * @param port    
     * @throws SocketException 
     */  
    public final void bind(String host, int port) throws SocketException {  
        socketAddress = new InetSocketAddress(host, port);  
        ds = new DatagramSocket(socketAddress);  
    }  
  
  
    /** 
     *      ,          . 
     * @return            
     * @throws IOException  
     * @throws ClassNotFoundException 
     */  
    public final byte[] receive() throws IOException, ClassNotFoundException {  
        packet = new DatagramPacket(buffer, buffer.length);  
        ds.receive(packet);  
        orgIp = packet.getAddress().getHostAddress(); 
        System.out.println(orgIp);
        return buffer; 
    }  
  
    /** 
     *           . 
     * @param bytes      
     * @throws IOException 
     */  
    public final void response(String info) throws IOException {  
        System.out.println("      : " + packet.getAddress().getHostAddress()  
                + ",  :" + packet.getPort());  
        DatagramPacket dp = new DatagramPacket(buffer, buffer.length, packet  
                .getAddress(), packet.getPort());  
        dp.setData(info.getBytes());  
        ds.send(dp);  
    }  
  
    /** 
     *          . 
     * @param bufsize      
     */  
    public final void setLength(int bufsize) {  
        packet.setLength(bufsize);  
    }  
  
    /** 
     *        IP  . 
     * @return      IP   
     */  
    public final InetAddress getResponseAddress() {  
        return packet.getAddress();  
    }  
  
    /** 
     *           . 
     * @return           . 
     */  
    public final int getResponsePort() {  
        return packet.getPort();  
    }  
  
    /** 
     *   udp   . 
     */  
    public final void close() {  
        try {  
            ds.close();  
        } catch (Exception ex) {  
            ex.printStackTrace();  
        }  
    }  
  
} 
package com.platform.net;

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

import struct.JavaStruct;

import com.platform.report.receive.OneSend;
import com.platform.report.receive.Response1;
import com.platform.report.send.DATA1;
import com.platform.report.send.Struct1;
import com.platform.util.ByteUtil;
  
/**    
 * UDP     ,          ,           . 
 * @author liukang
 */  
public class UdpClientSocket {  
	
	//  buffer
    private byte[] buffer = new byte[1200];  
  
    private DatagramSocket ds = null;  
  
    /** 
     *     ,  UDP    
     * @throws Exception 
     */  
    public UdpClientSocket() throws Exception {  
        //ds = new DatagramSocket();  
        ds = new DatagramSocket(21168);
    }  
      
    /** 
     *       ,      bind      . 
     * @param timeout      
     * @throws Exception 
     */  
    public final void setSoTimeout(final int timeout) throws Exception {  
        ds.setSoTimeout(timeout);  
    }  
  
    /** 
     *       . 
     * @return        
     * @throws Exception 
     */  
    public final int getSoTimeout() throws Exception {  
        return ds.getSoTimeout();  
    }  
  
    public final DatagramSocket getSocket() {  
        return ds;  
    }  
  
    /** 
     *              . 
     * @param host         
     * @param port       
     * @param bytes         
     * @return           
     * @throws IOException 
     */  
    public final DatagramPacket send(final String host, final int port,  
            final byte[] bytes) throws IOException { 
    	
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress  
                .getByName(host), port); 
        
        ds.send(dp);  
        return dp;  
    }  
  
    /** 
     *               . 
     * @param lhost       
     * @param lport       
     * @return               . 
     * @throws Exception 
     */  
    public final byte[] receive(final String lhost, final int lport)  
            throws Exception {  
        DatagramPacket dp = new DatagramPacket(buffer, buffer.length);  
        ds.receive(dp);  
        //String info = new String(dp.getData(), 0, dp.getLength());  
        return buffer;  
    }  
  
    /** 
     *   udp  . 
     */  
    public final void close() {  
        try {  
            ds.close();  
        } catch (Exception ex) {  
            ex.printStackTrace();  
        }  
    }  
    
} 

udpの問題が解決したら、難点はどのように値を伝えるかです.上のコードからudp伝値はbyte配列を利用していることがわかる.
しかし,対応するbyte配列をどのように組み立てるかが問題となっている.
ネットワーク通信に詳しい学生は、ネットワーク伝送バイトには大端小端の問題があり、ネットワークバイト順は記憶バイト順とは異なる問題があることを知っているかもしれません.
エンド・ツー・エンド・モードhttp://blog.csdn.net/hackbuteer1/article/details/7722667
Javaにバイトを操作させるのは無理ですが、まずjavaの各タイプが占めるバイト数を見てみましょう.
Int:4バイトShort:2バイトLong:8バイトByte:1バイトChar:2バイトFloat:4バイトDouble:8バイト
Cデータ型と占有バイト数:
16ビットコンパイラ
char:1バイト
char*(ポインタ変数):2バイト
short int:2バイト
int:2バイト
unsigned int:2バイト
float:4バイト
double:8バイト
long:4バイト
long long:8バイト
unsigned long:4バイト
32ビットコンパイラ
char:1バイト
char*(ポインタ変数):4バイト(32ビットのアドレス空間は2^32、すなわち32ビット、すなわち4バイト.同理64ビットコンパイラ)
short int:2バイト
int:4バイト
unsigned int:4バイト
float:4バイト
double:8バイト
long:4バイトlong long:8バイト
unsigned long:4バイト
64ビットコンパイラ
char:1バイト
char*(ポインタ変数):8バイト
short int:2バイト
int:4バイト
unsigned int:4バイト
float:4バイト
double:8バイト
long:8バイトlong long:8バイト
unsigned long:8バイト
異なるコンパイラのCの各タイプのデータに占めるバイト数が異なる場合、高低バイトの問題を考慮せずにjavaで記述すると拡張性が悪く、1バイトごとに整列する必要があります.
この問題にぶつかって,二つの方法を思いつく.
1つはファイルキャッシュであり、ファイルをデータ交換の媒体として利用し、例えばwebservice間でxml呼び出しを利用する
もう1つの方法はjavaで通信をするのではなく、CでCとCを通信させ、Cコンパイラを交換するにはダイナミックリンクライブラリを再コンパイルするだけでよい.
1つ目の実装はより簡単ですが、研究所はコードの行を変更することに同意しません.これが約束の協力です!
JNI定義方法:
1.まずjavaクラスを定義します.ダイナミックリンクライブラリのロードに注意してください.
public class Model {
	static{
		System.load("/SimulationPlatform/src/main/java/com/platform/jni/model.dylib");
	}
	
	public native void model1(DATA1 data);
	
}
2.JAvacコンパイルclassファイルの形成
javac -classpath ~/Documents/phpworkspace/SimulationPlatform/src/main/java/Model.java
3.javahはc言語ヘッダファイルを形成する
javah -classpath ~/Documents/phpworkspace/SimulationPlatform/src/main/java/com.platform.jni.Model
4.c言語プログラムを作成し、各タイプの変換方法はプログラム上にある.
gcc -fPIC -D\_REENTRANT -I/Library/Java/JavaVirtualMachines/jdk1.7.0_75.jdk/Contents/Home/include/-I/Library/Java/JavaVirtualMachines/jdk1.7.0_75.jdk/Contents/Home/include/darwin -c model.c
JNIEXPORT void JNICALL Java_com_platform_jni_Model_model1
  (JNIEnv *env, jobject obj1, jobject obj2){
  	struct DATA1 data2;
	int len;
	int i,j;

	jclass class = (*env)->GetObjectClass(env,obj2);//  class
	printf("get class right
"); /* char s1*/ jfieldID s1id = (*env)->GetFieldID(env,class,"s1","C"); jchar s1 = (*env)->GetCharField(env,obj2,s1id); data2.s1 = s1-'0'; /* char */ /* float speed*/ jfieldID speedid = (*env)->GetFieldID(env,class,"speed","F"); jfloat speed = (*env)->GetFloatField(env,obj2,speedid); data2.speed = speed; printf("%f
",speed); /* float */ /* float ang*/ jfieldID angid = (*env)->GetFieldID(env,class,"ang","F"); jfloat ang = (*env)->GetFloatField(env,obj2,angid); data2.ang = ang; printf("%f
",ang); /* float */ /* float fre*/ jfieldID freid = (*env)->GetFieldID(env,class,"fre","F"); jfloat fre = (*env)->GetFloatField(env,obj2,freid); data2.fre = fre; printf("%f
",fre); /* float */ /* float bre*/ jfieldID breid = (*env)->GetFieldID(env,class,"bre","F"); jfloat bre = (*env)->GetFloatField(env,obj2,breid); data2.bre = bre; printf("%f
",bre); /* float */ /* float cre*/ jfieldID creid = (*env)->GetFieldID(env,class,"cre","F"); jfloat cre = (*env)->GetFloatField(env,obj2,creid); data2.cre = cre; printf("%f
",cre); /* float */ /* float distence*/ jfieldID distenceid = (*env)->GetFieldID(env,class,"distence","F"); jfloat distence = (*env)->GetFloatField(env,obj2,distenceid); data2.distence = distence; printf("%f
",distence); /* float */ /* float ang1*/ jfieldID ang1id = (*env)->GetFieldID(env,class,"ang1","F"); jfloat ang1 = (*env)->GetFloatField(env,obj2,ang1id); data2.ang1 = ang1; printf("%f
",ang1); /* float */ /* float ang2*/ jfieldID ang2id = (*env)->GetFieldID(env,class,"ang2","F"); jfloat ang2 = (*env)->GetFloatField(env,obj2,ang2id); data2.ang2 = ang2; printf("%f
",ang2); /* float */ /* float time*/ jfieldID timeid = (*env)->GetFieldID(env,class,"time","F"); jfloat ftime = (*env)->GetFloatField(env,obj2,timeid); data2.time = ftime; printf("%f
",ang2); /* float */ /* float cy1*/ jfieldID cy1id = (*env)->GetFieldID(env,class,"cy1","F"); jfloat cy1 = (*env)->GetFloatField(env,obj2,cy1id); data2.cy1 = cy1; printf("%f
",cy1); /* float */ /* float ss*/ jfieldID ssid = (*env)->GetFieldID(env,class,"ss","F"); jfloat ss = (*env)->GetFloatField(env,obj2,ssid); data2.ss = ss; printf("%f
",ss); /* float */ /* float ang3*/ jfieldID ang3id = (*env)->GetFieldID(env,class,"ang3","F"); jfloat ang3 = (*env)->GetFloatField(env,obj2,ang3id); data2.ang3 = ang3; printf("%f
",ang3); /* float */ /* float ang4*/ jfieldID ang4id = (*env)->GetFieldID(env,class,"ang4","F"); jfloat ang4 = (*env)->GetFloatField(env,obj2,ang4id); data2.ang4 = ang4; printf("%f
",ang4); /* float */ /* char type1*/ jfieldID type1id = (*env)->GetFieldID(env,class,"type1","C"); jchar type1 = (*env)->GetCharField(env,obj2,type1id); data2.type1 = type1-'0'; /* char */ /* char type2*/ jfieldID type2id = (*env)->GetFieldID(env,class,"type2","C"); jchar type2 = (*env)->GetCharField(env,obj2,type2id); data2.type2 = type2-'0'; /* char */ /* char type3*/ jfieldID type3id = (*env)->GetFieldID(env,class,"type3","C"); jchar type3 = (*env)->GetCharField(env,obj2,type3id); data2.type3 = type3-'0'; /* char */ /* char len1*/ jfieldID len1id = (*env)->GetFieldID(env,class,"len1","C"); jchar len1 = (*env)->GetCharField(env,obj2,len1id); data2.len1 = len1-'0'; /* char */ /* char len2*/ jfieldID len2id = (*env)->GetFieldID(env,class,"len2","C"); jchar len2 = (*env)->GetCharField(env,obj2,len2id); data2.len2 = len2-'0'; /* char */ /* char file1*/ jfieldID file1id = (*env)->GetFieldID(env,class,"file1","[C");// jcharArray file1array = (jcharArray)(*env)->GetObjectField(env,obj2,file1id);// len = (*env)->GetArrayLength(env,file1array); jchar file1[len];//char (*env)->GetCharArrayRegion(env,file1array,0,len,file1); for( i = 0 ;i<len;i++){ printf("%c
",file1[i]); data2.file1[i] = file1[i]; } /* char */ /* char file2*/ jfieldID file2id = (*env)->GetFieldID(env,class,"file2","[C");// jcharArray file2array = (jcharArray)(*env)->GetObjectField(env,obj2,file2id);// len = (*env)->GetArrayLength(env,file2array); jchar file2[len];//char (*env)->GetCharArrayRegion(env,file2array,0,len,file2); for( i = 0 ;i<len;i++){ printf("%c
",file2[i]); data2.file2[i] = file2[i]; } /* char */ /** **/ struct sockaddr_in out; memset(&out,0,sizeof(out)); out.sin_family = AF_INET; out.sin_port = htons(PORT); out.sin_addr.s_addr = inet_addr(IP); int s; len = sizeof(struct sockaddr_in); s = socket(AF_INET,SOCK_DGRAM,0); if(s == -1){ printf("can not create socket
"); } int flag = sendto(s,(char*)&data2,sizeof(data2),0,(struct sockaddr *)&out,len); if(flag == -1){ printf("socket wrong!
"); } close(s); /** **/ }

5.ダイナミックリンクライブラリを形成し、私はMacを使っているのでdylibを形成します.
gcc -shared model.o -o model1.dylib
ダイナミックリンクライブラリが形成されるとnativeメソッドを呼び出すことでデータを送信することができる.javaで受信すればいいです.