1

I have data that I read from a socket and I know it has the following format:

[2bytes][8bytes][2bytes] = 12 bytes

That I want to read separately; and the values are in Hex. I actually captured that data a while ago in PHP and saved it to files and I can view it properly using od (unix):

$ od -h myFile
$ 0000000 02eb 02fe fe02 fefe 02fe 02fe 000a
$ 0000015 

That, has a CR and LF at the end, resulting in 14 bytes. How can I obtain those values in Java reading from a socket? For instance how do I get that "02eb" (2 bytes) and convert it to a decimal value?

I am already reading from the socket, last thing I tried was:

mMessage = mBRin.readLine();
byte[] bytes = mMessage.trim().getBytes()

But that gives me 18 bytes in the array.

If it helps, in PHP to get that first part I did:

$input = socket_read($value,13,PHP_BINARY_READ);
$trim_input = trim($input);
$float_head = hexdec(bin2hex(substr($input,0,2)));

I think I am not understanding this, which may be the answer

Community
  • 1
  • 1
quinestor
  • 1,432
  • 4
  • 19
  • 40

2 Answers2

2
Socket socket = ......;
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        short f1 = dis.readShort();
        long f2 = dis.readLong();
        sort f3 = dis.readShort();

To print the values in hex use String.format("%x",f1); Hope it helps ...

sharadendu sinha
  • 827
  • 4
  • 10
  • Thank you, this is it. +1 I can already understand that no decimal conversion is needed as the long and short values are concptually that. I'm waiting on user1657364's answer since it's more general – quinestor Sep 19 '12 at 12:11
2

I have data that I read from a socket and I know it has the following format:

[2bytes][8bytes][2bytes] = 12 bytes

If you already have code to read bytes from a socket, you can use a ByteBuffer to convert the bytes to short, int, long etc. values.

Socket s = .....;

InputStream in = s.getInputStream();
byte [] buf = new byte[12];

// read 12 bytes from socket into bytes
in.read(buf);

ByteBuffer bb = ByteBuffer.allocate(buf.length);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(buf);
bb.flip();
short short1 = bb.getShort();
long long1 = bb.getLong();
short short2 = bb.getShort();

Note the call to set the byte buffer to little endian.

When you did the od command you got output similar to the following (this output comes from a file I created on my system to mimic yours). The od -h command reads the bytes from the file, puts them together as 2-byte shorts in little endian mode then prints out the short values in hex.

$ od -h binary.dat 
0000000      02eb    02fe    fe02    fefe    02fe    02fe    000a        
0000015

However if you use the -tx1 you see the bytes in the real order they appear in the file.

$ od -tx1 binary.dat
$ 0000000    eb  02  fe  02  02  fe  fe  fe  fe  02  fe  02  0a
$ 0000015

If you run this on your file I think you will see that it is really 13 bytes not 14 bytes and is terminated by a single LF, not CRLF. The "extra" byte you saw was a "present" from od -h is does not actually exist in file.

Anyhow, The first byte is value 235 (EB in hex). The second byte is 2. The question is - what is the correct value for that first short want. If, according to your socket protocol, the data is serialized in little endian mode, the value of those two bytes concatenated into a short is 02EB hex or 747. If the socket protocol uses big endian, then the value is EB02 hex or 60162.

The ByteBuffer approach gives you flexibility and allows you to read/write in either big-endian or little endian. It also allows you to separate the reading of data off the socket (into byte arrays) then later converting the data into numbers. This may make it easier for unit testing since you can create byte arrays for various test cases and make sure your parsing code works as expected.

The DataInputStream approach in sharadendu's answer will also work - but only if the socket protocol is big-endian. DataInputStream is hard-coded to big-endian.

Guido Simone
  • 7,912
  • 2
  • 19
  • 21
  • Thank you for your answer, with sharadendu's answer I can see the values but wit your approach I see incorrect values. I feel this is the answer.. did you try yourself what you wrote? I load buf properly, buy already in short short1 = bb.getShort(); I get a value that is not equal to short f1 = dis.readShort(); – quinestor Sep 19 '12 at 11:54
  • Oh and I think that the problem comes from getBytes, because from there the resulting array is 19 bytes – quinestor Sep 19 '12 at 12:06
  • Change bb.order(ByteOrder.LITTLE_ENDIAN) to bb.order(ByteOrder.BIG_ENDIAN) and my snippet will produce the same results as the DataInputStream sample. Your example made me think the data was little endian. If the DataInputStream is returning the expected values, then your data stream is big endian – Guido Simone Sep 19 '12 at 12:14
  • I already tried this, , do you know if mMessage().getBytes() is the appropiate way to build buf? – quinestor Sep 19 '12 at 12:32
  • Updated the sample. mMessage is a String? No. Based on your description of the protocol - binary not text - you should not be using strings anywhere. – Guido Simone Sep 19 '12 at 12:47
  • One last thing. My sample does not show it but in production you need to check the return value of in.read() and make sure that you really read in 12 (or whatever). If it is less then 12 you'll need to do another read, specifying offset and length until the buffer fills up – Guido Simone Sep 19 '12 at 13:03
  • When you are reading from socket the Byte order is always BIG_ENDIAN. (Correct me if i am wrong). So I dont quite see the value add of using ByteBuffer in this scenario. – sharadendu sinha Sep 19 '12 at 15:27