Colin
Colin

Reputation: 735

Setting a Java Byte Array Size from Packet Header

A piece of Java code is residing on a server expecting about 64 bytes of information from a piece of hardware, sent via TCP. The packet has a 10 byte header. The first byte is a protocol identifier, the second two bytes gives the total number of bytes in the packet, including all the header bytes and checksum. The last 7 bytes are a UID.

Server Code:

public void run () throws Exception
    {

        //Open a socket on localhost at port 11111
        ServerSocket welcomeSocket = new ServerSocket(11111);


        while(true) {

            //Open and Accept on Socket
            Socket connectionSocket = welcomeSocket.accept();

            //Alt Method

            DataInputStream dis = new DataInputStream(connectionSocket.getInputStream());

            int len = dis.readInt();
            byte[] data = new byte[len];
            if (len > 0) {
                dis.readFully(data);
            }
            System.out.println("Recv[HEX]: " + StringTools.toHexString(data));
    }
}

The issue is my readInt() line, that takes the first four bytes, however I need to determine the length based on the second two bytes. How can this be achieved?

And secondly, is my stringTools.toHexString(data) correct to dump the received buffer which I know should be readable as a HEX string?

Note: This question has its root here: Java TCP Socket Byte Heap Memory Issue

Upvotes: 0

Views: 2632

Answers (2)

OscarRyz
OscarRyz

Reputation: 199264

You can use ByteBuffer to read the int in the last two bytes

import static java.lang.System.out;
import java.nio.ByteBuffer;
class B {
    public static void main( String ... args ) {
        // test value
        int a = 1238098;

        // convert it into an arrays of bytes
        ByteBuffer b = ByteBuffer.allocate(4);
        b.putInt(a);
        byte [] r = b.array();
        // read last two 
        int size = ByteBuffer.wrap(new byte[]{0x0,0x0, r[2], r[3]}).getInt();

        // print it 
        out.println("Original: " + String.format("%32s%n" , Integer.toString(a,2)).replace(' ', '0'));
        out.printf("Last two: %32s%n" , Integer.toString(size,2));
        out.printf("Decimal : %d%n" ,  size );
    }
}

Output:

Original: 00000000000100101110010001010010

Last two:                 1110010001010010
Decimal : 58450

However I would recommend to follow @Jiri answer about read using InputStream.read() instead of DateInputStream

Upvotes: 0

Jiri Tousek
Jiri Tousek

Reputation: 12440

Only use DataInputStream if the other side is using DataOutputStream or it's exact format. The integers, for example, may be encoded big-endian or little-endian - DataOutputStream uses big-endian notation, if the other side uses different encoding, you cannot use DataInputStream. Using InputStream.read() gives you more control if you need it.

Now, since the format of message as you stated starts with one byte for protocol identifier, you first need to read that as a byte (dis.readByte() or InputStream.read()) and either check that the protocol is what you expect or handle different protocols. Then you read the message length, etc.

Upvotes: 2

Related Questions