2010-01-28 3 views
3

일부 중간 네트워크를 통해 전송되고 Java 코드로 직렬 링크를 통해 수신되는 C 구조가 있습니다. Java 코드는 나에게 바이트 배열을 제공하여 원래 구조로 다시 패키징하려고합니다. 이제 수신 코드가 C 언어 인 경우 간단합니다. 어떤 간단한 방법으로 Java에서 C struct에 byte []를 재 패키징 할 수 있습니까? 내가 자바에서 최소한의 경험을 가지고 있지만이 나던은 일반적인 문제로 나타납니다 또는 내가 찾을 수있는 모든 FAQ에서 해결. Java에서 액세스되는 C 구조

는 참고는 C 구조체 오히려 원시 데이터를 보내는 것보다이 인코딩 C 및 Java 수를 모두 사용하기 위해가는 더 나을 수도, 당신은 링크의 양쪽 끝을 제어 할 수 있습니다 가정

struct data { 
    uint8_t  moteID; 
    uint8_t  status; //block or not 
    uint16_t tc_1; 
    uint16_t tc_2; 
    uint16_t panelTemp; //board temp 
    uint16_t epoch#; 
    uint16_t count; //pkt seq since the start of epoch 
    uint16_t TEG_v; 
    int16_t TEG_c;  
}data; 

답변

1

입니다. JSON 또는 프로토콜 버퍼를 살펴보십시오.

+0

그래, C 에서조차도 한쪽 끝이 그 바이트를 어떻게 포장했는지에 따라 매우 위험했을 것입니다.최소한 한 번에 하나의 요소를 순서대로 정렬하는 알려진 바이트로 숫자를 전송해야하므로 같은 방식으로 다시 읽을 수 있습니다. – PSpeed

+0

JSON에서이 구조체에 많은 대역폭 오버 헤드가 발생할 수 있습니다. – Crashworks

+0

@PS 속도가 네트워크 바이트 순서입니다. @ Crashworks 아마도 가능합니다. 프로토콜 버퍼는 내가 아는 것보다 더 나은 작업을 수행 할 것입니다. – Andrew

2

이것은 바이트/문자의 배열로 끝날 수 있도록, 당신은 데이터 구조체가있는 경우 C.

에 C에서 보낼 때 어떻게 캐스팅하기가 어려울 수 있습니다 그리고 당신은 단지 맹목적으로 그것을 보내 때로는 다른 끝에 그것을 디코딩하는 큰 문제로 끝날 수 있습니다. 이것은 때때로 컴파일러가 데이터가 구조체에 압축되는 방식을 최적화하기로 결정했기 때문에 원시 바이트에서는 코드 작성 방식에 따라 모양이 어떻게되는지 정확하게 볼 수 없기 때문입니다. 정말 컴파일러에 달려 있습니다!

패킹을 최적화되지 않게 만드는 데 사용할 수있는 컴파일러 pragma가 있습니다. 또 다른 문제는 바이트 수를 지정하지 않고 "긴"그냥 "INT"를 사용하는 경우 64분의 32 비트 비트 문제이며, C/C++ Preprocessor Reference - pack

참조하십시오 ...하지만 당신은 :-)

에게 행한

불행히도 Java는 실제로 구조체를 가지고 있지 않습니다 ...하지만 클래스의 동일한 정보를 나타냅니다. 내가 추천하는 것은 변수로 구성된 클래스를 만들고, (전송 후 정확성을 확인한 후에) 수신 된 패킷에서 바이트를 꺼내는 맞춤식 압축 풀기 함수를 만든 다음 수업.

당신은이

Data convertBytesToData(byte[] dataToConvert) 
{ 
    Data d = Data(); 
    d.moteId = (int)dataToConvert[0]; 
    d.status = (int)dataToConvert[1]; 
    d.tc_1 = ((int)dataToConvert[2] << 8) + dataTocConvert[3]; // unpacking 16-bits 
    d.tc_2 = ((int)dataToConvert[4] << 8) + dataTocConvert[5]; // unpacking 16-bits 
} 
가 내가 16 비트의 주위 길을 잘못 풀고있을 수 있습니다

,이에 따라 달라 바이트 배열을받을 때

class Data 
{ 
    public int  moteID; 
    public int  status; //block or not 
    public int  tc_1; 
    public int  tc_2; 
} 

같은 데이터 클래스는 다음, 당신이 좋아하는 뭔가를 할 수 있습니다 당신의 C 시스템의 엔디안이지만, 당신은 놀 수 있고 그것의 옳고 그름을 볼 수있을 것입니다. 나는 자바와 함께 언젠가는 연주하지 않았지만 요즘에는 내장 함수에 바이트 []가있을 수 있기를 바랍니다. 어쨌든 C#이 있다는 것을 알고 있습니다.

높은 데이터 전송을 수행하지 않는다면, JSON과 프로토콜 버퍼를 자세히 살펴보십시오! 당신이 뭘 하려는지

+0

모두에게 감사드립니다. 실제로 모든 것이 네트워크 순서로 전송되었는지 확인했습니다. Java에서 너무 많이 다루고 싶지 않기 때문에 위의 Java 클래스 패킹 솔루션이 최상의 솔루션 인 것 같습니다. – intiha

+0

@intiha, 아, 우리는 당신이 C struct를 그 바이트의 메모리 덤프로 쓰고 있다고 믿게되었다. 실제로 각 개별 멤버를 쓰는 경우 (따라서 바이트 순서를 올바르게 제어 할 수있는 경우) 더 쉽고 해결할 수있는 문제입니다. – PSpeed

0

는 몇 가지 이유로 문제가있다 :

  • 다른 C 구현은 다른 방법으로 uint16_t (및 int16_t) 값을 나타냅니다. 경우에 따라서는 구조체가 메모리에 배치 될 때 가장 중요한 바이트가 첫 번째가됩니다. 다른 경우에는 최하위 바이트가됩니다.

  • 다른 C 컴파일러는 구조체의 필드를 다르게 패킹 할 수 있습니다. 따라서 필드가 재정렬되었거나 패딩이 추가되었을 가능성이 있습니다 (예를 들어).

그래서이 모든 방법은 당신이 밖으로 정확히 struct이 ... 배치됩니다 파악해야 그냥 때 C 컴파일러 또는 C의 대상 플랫폼을 변경하는 경우이/변경되지 않습니다 희망하는 것이 무엇인지.

그렇다고해서 "endian-ness"를 선택할 수있는 임의의 바이너리 데이터 스트림을 디코딩하는 Java 라이브러리를 찾을 수 없습니다. DataInputStream 및 DataOutputStream 클래스는 대답 일 수 있지만 우선 순위가 높은 바이트를 먼저 보내거나 기대하도록 명시 적으로 정의됩니다. 데이터가 다른 방향으로 오게되면 자바 비트를 수정해야합니다.

편집 : 실제로 (@Kevin 브록은 지적으로) java.nio.ByteBuffer 바이너리 버퍼에서 다양한 데이터 유형을 가져 오는 때 엔디안을 지정할 수 있습니다.

+0

다른 바이트 순서를 지원하는 "java.nio.ByteBuffer"를 사용할 수 있으며 특정 유형을 검색 할 수 있습니다. –

7

전 항상 네트워크 바이트 순서로 번호를 보내는 것이 좋습니다. 이렇게하면 다음과 같은 문제가 해결됩니다.

  1. 구조체에 대한 컴파일러 관련 단어 경계 생성.
  2. 하드웨어에 특정한 바이트 순서 (전송 및 수신).

또한 Java 번호는 Java를 실행하는 플랫폼 (JavaBeans 사양에는 특정 바이트 순서가 필요함)과 상관없이 항상 네트워크 바이트 순서로 저장됩니다.

스트림에서 비트를 추출하는 데 매우 적합한 클래스는 임의의 바이트 배열을 래핑 할 수있는 java.nio.ByteBuffer입니다. java.nio의 I/O 클래스에서 온 것만이 아닙니다. 가능하다면 (예 : 비트 시프트 등) 원시 타입 값을 추출하는 코드를 직접 넘겨서는 안됩니다. 코드를 잘못 입력하는 것이 쉽기 때문에 코드는 같은 타입의 모든 인스턴스에 대해 동일하고 충분히 있습니다 이것을 제공하는 표준 클래스를 제공합니다. 예를 들어

:

이제
public class Data { 

    private byte moteId; 
    private byte status; 
    private short tc_1; 
    private short tc_2; 
    //...etc... 
    private int tc_2_as_int; 

    private Data() { 
     // empty 
    } 

    public static Data createFromBytes(byte[] bytes) throws IOException { 
     final Data data = new Data(); 
     final ByteBuffer buf = ByteBuffer.wrap(bytes); 

     // If needed... 
     //buf.order(ByteOrder.LITTLE_ENDIAN); 

     data.moteId = buf.get(); 
     data.status = buf.get(); 
     data.tc_1 = buf.getShort(); 
     data.tc_2 = buf.getShort(); 
     // ...extract other fields here 

     // Example to convert unsigned short to a positive int 
     data.tc_2_as_int = buf.getShort() & 0xffff; 

     return data;   
    } 

} 

, 그냥 Data.createFromBytes(byteArray) 전화, 하나 만듭니다.

Java는 부호없는 정수 변수가 없지만 정확히 같은 비트 패턴으로 검색됩니다. 따라서 상위 비트가 설정되지 않은 부분은 사용될 때 정확히 동일합니다. 서명되지 않은 숫자를 예상 할 경우 상위 비트를 처리해야합니다. 때로는 다음에 더 큰 정수 유형 (byte -> short; short -> int; int -> long)에 값을 저장하는 것을 의미합니다.

편집 : (부호있는 32 비트) tc_2_as_int와 부호없는 값을 가진 intshort (16 비트 서명) 변환하는 방법을 보여주기 위해 예를 업데이트했습니다.

바이트 순서를 변경할 수없고 네트워크 순서가 아닌 경우 은 여전히 ​​값을 검색하기 전에 buf.order(ByteOrder.LITTLE_ENDIAN);으로 여기서 사용자에게 서비스를 제공 할 수 있습니다.

+0

좋은, 나는 자바 사람이 내가 라이브러리 기능 내장에 사용하여 설명하려고했던 것을하는 방법을 보여줄 수있을 것이라는 것을 알고 있었다 :-) – Fuzz

+0

나는 실제로 지금이 해결책을 가고있다. 많은 문제를 해결할 수 있습니다. 감사. – intiha