简体   繁体   中英

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM