2011-06-29 43 views
4

我對Java和C編程相當新穎,需要一些幫助。 所以我有一個C應用程序發出的結構通過UDP: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)); 

} 

現在我需要能夠通過UDP接收這個數據在Java和填充的對象與這些值。我可以得到第一個字符串(名稱),但不知道如何去獲取剩餘的項目。

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

由於存在endian和bit packing問題,您不應該一般性地將C結構寫入網絡。相反,您需要經過編組和編碼過程,以便攜式網絡編碼格式寫出每個結構存儲器。另一面讀取便攜式網絡格式並存儲它,但需要。

這就是所有Internet標準RFCish協議的工作原理。他們定義了所有字段的順序,編碼,字節順序和其他語義。是的,他們有時會安排它,這樣一個精心構造的結構可以覆蓋在網絡緩衝區上,但即使如此,他們通常需要在緩衝區上執行htons()或朋友,才能使它們進入正確的字節順序。

我建議採取這種方法。

讀你的結構,它沒有以促進直接在網絡上發送的方式佈局。例如,很可能在結構中存在漏洞,例如,其他系統很難正確解碼。

+0

這聽起來像是一個明智的長期解決方案。推薦使用跨語言的方法是什麼?我應該走下Google的協議緩衝區路線嗎?結構相當簡單,不必改變。這在運行時也需要很快。請將您指向正確的方向,謝謝。 – Andrey

+0

@Andrey:對於一個尺寸適中的結構,我只需手動完成。 '寫(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);寫(fd,tmpuint,sizeof(tmpuint));'等等獎勵點,如果你使用'u_int8_t'和'u_int16_t'和'u_int32_t'來減輕你對各種平臺上char/short/int/long大小的依賴。另一方面閱讀它,將網絡訂單轉換回主機訂單,然後將其存儲,但無論您需要如何。 –

1

一種方法是從byte []數據創建一個java.io.ByteArrayInputStream,並將其包裝在一個DataInputStream中,該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字符),短褲,整數和多個字符串的方法。

該代碼非常簡單。但是,正如其他人所指出的......這仍然是一個糟糕的主意。如果可能的話,請使用JSON或XML。在發送之前,將UTF-8格式的JSON或XML存儲在UDP數據報中。在接收端,將UTF-8轉換回Java String(包含UTF-8的字節數組上的new String()),然後解組JSON或XML。