Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way for converting to bigendian for network submission

Tags:

python

sockets

I need to get an int through the network. Is this the proper way to convert to bytes in big-endian?

pack("I",socket.htonl(integer_value))

I unpack it as:

socket.ntohl(unpack("I",data)[0])

I noticed that pack-unpack also have the <> to use for endian conversion so I am not sure if I could just directly use that instead or if htonl is safer.

like image 737
Michael Avatar asked Oct 26 '25 07:10

Michael


1 Answers

You should use only the struct module for communicating with another system. By using the htonl first, you'll end up with an indeterminate order being transmitted.

Since you need to convert the integer into a string of bytes in order to send it to another system, you'll need to use struct.pack (because htonl just returns a different integer than the one passed as argument and you cannot directly send an integer). And in using struct.pack you must choose an endianness for that string of bytes (if you don't specify one, you'll get a default ordering which may not be the same on the receiving side so you really need to choose one).

Converting an integer to a sequence of bytes in a definite order is exactly what struct.pack("!I", integer_value) does and a sequence of bytes in a definite order is exactly what you need on the receiving end.

On the other hand, if you use struct.pack("!I", socket.htonl(integer_value)), what does that do? Well, first it puts the integer into big-endian order (network byte order), then it takes your already big-endian integer and converts it to bytes in "big-endian order". But, on a little endian machine, that will actually reverse the ordering again, and you will end up transmitting the integer in little-endian byte order if you do both those two operations.

But on a big-endian machine htonl is a no-op, and then you're converting the result into bytes in big-endian order.

So using ntohl actually defeats the purpose and a receiving machine would have to know the byte-order used on the sending machine in order to properly decode it. Observe...

Little-endian box:

>>> print(socket.htonl(27))
452984832
>>> print(struct.pack("!I", 27))
b'\x00\x00\x00\x1b'
>>> print(struct.pack("!I", socket.htonl(27)))
b'\x1b\x00\x00\x00'

Big-endian box:

>>> print(socket.htonl(27))
27
>>> print(struct.pack("!I", 27))
b'\x00\x00\x00\x1b'
>>> print(struct.pack("!I", socket.htonl(27)))
b'\x00\x00\x00\x1b'
like image 124
Gil Hamilton Avatar answered Oct 27 '25 23:10

Gil Hamilton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!