Q:

how to decode C stuct like packets - with java socket programming

new to socket programming in java!.   i am trying my level best to understand java socket programming, and how to decode 'C' strut like packets.
The client is python which sends packet between tags,
 example Payload : <tag1> data packet 1</tag1><tag2>data packet 2</tag2>
Have a c code to which received the payload and decode the payload with structure , all the tags are of 30 bytes, data packet 1, 2,.. n will be of different structure
I am fairly new to java program, after searching through the web, i could write a socket server which receives payload from client, now facing problem in decoding the data packets.
I could display the bytes. so Used Arrays.copyOfRange method to get data.
The packet data are something represented as below,
typedef struct {

  unsigned char     dataType;
  unsigned char     value[4];

} GEN_VAL

typedef struct {

  unsigned char     dataType;
  unsigned char     numBytes;
  unsigned char     value[32];

} GEN_STR_32;

typedef struct {

    char           startTag[32];
    GEN_STR_32     c_code;
    GEN_STR_32     c_name;
    GEN_STR_32     c_info;

    GEN_VAL        i_type;
    GEN_VAL        i_count1;
    GEN_VAL        i_count2;
    char           endTag[32];

} DATA_PACKET_1;

I receive buffer with following code snippet
  DataInputStream inStream = new DataInputStream
                        (new BufferedInputStream(socket.getInputStream()));

 while ( ( noOfBytes = (int)inStream.read(recvBuff)) != -1)
{
 cDecode mydecode = new cDecode();
 mydecode.decodePacket(noOfBytes, recvBuff);
}

cDecode.java
public void decodePacket(int TotalBytes, byte[] BuffRecv) 
{
    byte[] GetTag = new byte[32];
    byte[] GEN_STR_32 = new byte[32];
    byte[] GEN_INT_4  = new byte[4];

     GetTag = Arrays.copyOfRange(BuffRecv,0,31);
     String TagStr = new String(GetTag).trim();  //get start tag 

     int startloc = 31;
     int offset = startloc + 32;
     GEN_STR_32 = Arrays.copyOfRange(Buff,startloc,offset);
     String cCode = new String(GEN_STR_32).trim();  // get value of cCode
     System.out.println("Code   :" + cCode );

     startloc = offset;
     offset = startloc + 32;
     GEN_STR_32 = Arrays.copyOfRange(Buff,startloc,offset);
     String cName = new String(GEN_STR_32).trim(); //get value of cName
     System.out.println("Name:" + cName );

     startloc = offset;
     offset = startloc + 32;
     GEN_STR_32 = Arrays.copyOfRange(Buff,startloc,offset);
     String cInfo = new String(GEN_STR_32).trim(); //get value of cName
     System.out.println("Info:" + cInfo );

     startloc = offset;
     offset = offset + 4;
     ByteBuffer iTypeByteBuff = ByteBuffer.wrap(GEN_DATA_INT_4);
     int iType= iTypeByteBuff .getInt();
     System.out.println("type :" + iType);

     startloc = offset;
     offset = offset + 4;
     // likewise used ByteBuffer for remaining integer data 
     // for receiving end tag, offset is added with 32!
}

first 3 data is string value    and
second 3 data have integer value
String value is displayed correctly.
finding problem in converting byte to integer, not sure whether i am using correct value for startloc and offset  in Arrays.copyOfRange method.
I tried this based on the information i got from net. 
I also read about having a separate class without methods for all data structures. but i cant find any complete example, as 'sizeof' is not available in java.
can some one guide me the correct way to decode packets in this scenario.

A:

If you think of the data as a stream to be read as a data type, you could extend DataInputStream to create a PacketInputStream that has a readDataPacket() method. Define a DataPacket class to hold the data from your C DATA_PACKET_1 struct.
First the classes to hold your data:
public class GenValue {
    private final byte dataType;
    private final byte[] value;

    public GenVal(byte dataType, byte[] value) {
        this.dataType = dataType;
        this.value = value;
    }

    public byte getDataType() {
        return dataType;
    }

    public byte[] getValue() {
        return value;
    }
}

public class DataPacket {
    private final String startTag;
    private final String code;
    private final String name;
    private final String info;
    private final GenValue type;
    private final GenValue count1;
    private final GenValue count2;
    private final String endTag;

    public DataPacket(String startTag, other args here...) {
        this.startTag = startTag;
        // Set the other properties from constructor args...
    }

    public String getStartTag() {
        return startTag;
    }

    // Add getters for the other properties...
}

And the DataInputStream implementation to decode your packets:
public class PacketInputStream extends DataInputStream {
    public DataPacket readDataPacket() throws IOException {
        String startTag = readGenStr32();
        String code = readGenStr32();

        // Do the same for name and info...
        ...

        GenValue type = readGenValue();
        GenValue count1 = readGenValue();
        GenValue count2 = readGenValue();

        // Read the endTag the same as the Strings above...
        ...

        return new DataPacket(startTag, code, name, info, type, count1, count2, endTag);
    }

    public String readGenStr32() throws IOException {
        byte[] strBuf = new byte[32];
        readFully(strBuf, 0, 32);
        return new String(strBuf).trim();
    }

    public GenValue readGenValue() throws IOException {
        byte dataType = readByte();
        byte[] value = new byte[4];
        readFully(value);
        return new GenValue(dataType, value);
    }
}

Calling code would do something like:
PacketInputStream in = new PacketInputStream((new BufferedInputStream(socket.getInputStream()));
DataPacket p = in.readDataPacket();
System.out.println("Start tag: " + p.getStartTag());
System.out.println("Code: " + p.getCode());
// Print other values of interest...

I would just override DataPacket.toString() and then do System.out.println(p), but there's enough code here already. Also, I would store primitive types instead of using a GenValue class, but I don't know enough about your actual data to work that out.

