2011-06-29 5 views
4

私はJavaとCの両方でプログラミングするのがかなり新しく、助けが必要です。 だから私は、UDP上の構造物を送り出すCアプリケーションを持っている:C UDPを使ったJavaオブジェクトへの構造

#include <sys/socket.h> 
#include <netinet/in.h> 
#include <stdio.h> 
#include <string.h> 


int main(int argc, char**argv) 
{ 
    int sockfd,n; 
    struct sockaddr_in servaddr,cliaddr; 

struct dataType { 
    char name[4]; 
    unsigned short did; 
    unsigned short sid; 
    unsigned short type:4,pri:2,cb:2,flags:8; 
    unsigned char pblock; 
    unsigned char tblock; 
    unsigned short mess; 
    unsigned int window:24; 
}; 

struct dataType sample_header; 
strcpy(sample_header.name,"TEST"); 
sample_header.did=23; 
sample_header.sid_id=1; 
sample_header.type=1; 
sample_header.pri=01; 
sample_header.cb=1; 
sample_header.flags=18; 
sample_header.pblock=10; 
sample_header.tblock=20; 
sample_header.mess3; 
sample_header.window=123890; 

sockfd=socket(AF_INET,SOCK_DGRAM,0); 
servaddr.sin_family = AF_INET; 
servaddr.sin_addr.s_addr=inet_addr(argv[1]); 
servaddr.sin_port=htons(6120); 
sendto(sockfd, (char *)&sample_header, (sizeof(struct dataType)),0,(struct sockaddr *)&servaddr,sizeof(servaddr)); 

} 

今、私はJavaでUDPを介してこのデータを受信し、これらの値を持つオブジェクトを移入することができるようにする必要があります。私は最初の文字列(名前)を取得できますが、残っている項目を取得する方法についてはわかりません。

import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.io.*; 
import java.net.*; 
import java.awt.*; 
import java.nio.*; 

public class UDPReceive { 
    public static void main(String args[]) { 
    try { 
     int port = 6120; 

     DatagramSocket dsocket = new DatagramSocket(port); 
     byte[] buffer = new byte[1024]; 
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
     while (true) { 
     dsocket.receive(packet); 
     byte[] data = packet.getData(); 
     String msg1 = new String(data, 0, 5); 
     System.out.println("Here is SOME :" + msg1); 
     packet.setLength(buffer.length); 
     } 
    } catch (Exception e) { 
     System.err.println(e); 
    } 
    } 
} 

私はGoogleのプロトコルバッファを見ましたが、明らかに両側の変更が必要です。 私はまた、最終的にこのデータをJavaオブジェクトからUDPに送り、C構造体に戻すことができる必要があります。

多くのありがとうございます。

答えて

3

一般に、エンディアンとビットパッキングの問題により、ネットワークにC構造を書き込むべきではありません。代わりに、ポータブルネットワークエンコーディング形式で各構造メモリを書き出すマーシャリングとエンコーディングプロセスを実行する必要があります。もう片面はポータブルネットワークフォーマットで読み込まれ、それを保存する必要があります。

これは、すべてのインターネット標準RFCishプロトコルがどのように機能するかです。それらは、順序、エンコーディング、エンディアン、およびすべてのフィールドの他のセマンティクスを定義します。はい、慎重に構築された構造をネットワークバッファにオーバーレイすることができるように配列を調整することもありますが、バッファでhtons()やfriendを実行して正しいエンディアンにする必要があることがよくあります。

このアプローチをとることをおすすめします。

構造体を読み込むと、ネットワーク上で直接送信されるようにレイアウトされていません。たとえば、構造に穴があり、他のシステムが正しくデコードするのが非常に難しいように見えるでしょう。

+0

これは賢明な長期的解決策のように聞こえる。クロスレングスに対応するためにこれを行う推奨方法は何ですか? Googleのプロトコルバッファーのルートを下げるべきですか?構造はかなり単純であり、変更する必要はありません。これは実行時にも高速にする必要があります。あなたが正しい方向に私を向けることができれば、感謝します。 – Andrey

+0

@Andrey:控えめなサイズの構造のために、私はそれを手動でやっています。 'write(fd、b.name、sizeof(b.name)); tmpushort = htons(b.did);書き込み(fd、tmpushort、sizeof(tmpushort)); tmpuchar = b.type;書き込み(fd、tmpuchar、sizeof(tmpuchar)); tmpuint = htonl(b.window); '' u_int8_t''と '' u_int16_t''と '' u_int32_t''を使ってchar/short/int/longの大きさに依存しないようにする場合のボーナスポイントです。反対側でそれを読んで、ネットワーク注文からホスト注文に変換して、それを保管しておく必要があります。 –

1

byte [] dataからjava.io.ByteArrayInputStreamを作成し、DataInputStreamにラップして、他のプリミティブ型を読み取るメソッドを提供します。

おそらくネットワークバイトオーダーで整数を伝えたいと思うでしょう。 C側では、ntohl、htonl、ntohs、htonsなどを使用できます。ビットフィールドを使用する場合は、Java側で手作業で翻訳する必要があります。

0

データをシリアル化してからjavaでデコードする必要があります。

void write_dataType(char* buff, dataType* data) 
    { 
    sprintf(buff, "%s\n%d\n", name, data.did); 
    } 

もちろん、実際のRPC technologyを使用することもできます。

0

いくつかの人々がすでにこの質問にかなり良い答えを示しています。 UDPデータグラムを介してc構造体を送信するだけで、時間の経過とともに問題が発生する可能性があります。 XMLまたはJSONを使用したシリアライゼーションは、柔軟性と送信者/受信者の独立性を大幅に向上させます。

これまで言われていたことは... Javaには、あなたが望むだけの些細なやり方があります。 ByteBufferを使用して受信UDPデータグラムからバイト配列をラップするだけです。 ByteBufferには、ByteBufferからバイト、文字(Unicode文字のJava文字)、shorts、int、およびlongを取得するためのメソッドがあります。

コードは非常に簡単です。しかし、他の人が指摘しているように...それはまだ悪い考えです。可能であれば、JSONまたはXMLを使用してください。送信する前に、JSONまたはXMLをUTF-8形式でUDPデータグラムに格納します。受信側では、UTF-8をJava String(UTF-8を含むバイト配列の新しいString()が正しく動作する)に変換してから、JSONまたはXMLをアンマーシャリングします。

関連する問題