0

I am currently writing a server in C++ and an Android app that revceives data from it using google protobuf. Currently I frame the data with the size, so basically I send

-----------------------------------------------------
| payload size (4byte, unsigned) | protobuf payload |
-----------------------------------------------------

I have no problem deserializing the stuff in Java, but how can I convert the bytes from the socket to an unsigned integer? The payload size is always a uint32_t that has been converted with htonl to network byte order. So Java needs to convert to host byte order and convert it to an Integer.

Nidhoegger
  • 4,973
  • 4
  • 36
  • 81
  • Possible duplicate of [Network byte order to host byte order conversion Java](https://stackoverflow.com/questions/42231549/network-byte-order-to-host-byte-order-conversion-java) – Etienne de Martel Dec 17 '18 at 17:21
  • @EtiennedeMartel its not a direct duplicate as I also need to know how to convert the bytes to uint32_t in the first place. – Nidhoegger Dec 17 '18 at 17:22
  • Java ints are already 32 bits, so that's that. – Etienne de Martel Dec 17 '18 at 17:25
  • @EtiennedeMartel and are they signed or unsinged? and how to get an int from a byte array? – Nidhoegger Dec 17 '18 at 17:27
  • Possible duplicate of [Convert a byte array to integer in Java and vice versa](https://stackoverflow.com/questions/7619058/convert-a-byte-array-to-integer-in-java-and-vice-versa) – SHR Dec 17 '18 at 17:28
  • 1
    @Nidhoegger in Java the int are always signed, – bruno Dec 17 '18 at 17:29
  • so then the question is not answered as the posted links do not cover the signed / unsigned. – Nidhoegger Dec 17 '18 at 17:30
  • the right conversion is C++ 32b unsigned -> Java long (64b signed) – bruno Dec 17 '18 at 17:31
  • @Nidhoegger protobuf manages by itself the byte order, do you not use it on one side ? – bruno Dec 17 '18 at 17:37
  • @bruno This is in the streaming message protocol layered on top of protobuf. See [here](https://developers.google.com/protocol-buffers/docs/techniques#streaming) for more information. – David Schwartz Dec 17 '18 at 18:49

1 Answers1

2

Okay, so, in Java, ints are always 32 bits, so you just need to read those four bytes and turn that into an int using ByteBuffer. You might think we'd need to specify a byte order, but it turns out that ByteBuffers reads bytes in big endian order by default, so that already works for the network order:

byte[] bytes = ...;
int size = ByteBuffer.wrap(bytes).getInt();

However, since all integers in Java are signed, then size above might end up negative if it's too big. You probably don't want that. You could cast it to long, but if the int is negative its sign will be extended, and you'll end up with a negative long.

The solution is to interpret it as a long, which, even though it is signed, is 64 bits and therefore big enough to represent a 32 bit unsigned integer. Thankfully, there's a method in Java 8 that does just that:

long actualSize = Integer.toUnsignedLong(size);

There you go, now you can play with the size.

Etienne de Martel
  • 34,692
  • 8
  • 91
  • 111