Search code examples
pythonsocketsbyteportsendto

Python: Creating 16-bit source and destination ports for a packet header


I'm creating a networking protocol in application space on top of UDP in python for homework. I need to represent the source port and destination port as 16-bit numbers. All attempts have failed.

The way I'm testing this is by creating a udp socket and looking at the return value of sendto(). Here's your typical socket code:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("127.0.0.1", 1234)

Ports range from 0 to 65535. Let's say I choose a port of 65000. I want sendto() to return 2 (2 bytes = 16 bits sent). Here's what I've tried:

I call the following and get:

>>>mySock.sendto(655000, addr)
TypeError: must be string or buffer, not int

Ok, let's try using bytes()

>>>mySock.sendto(bytes(65000), addr)
5

Hm, that's not what I want. That is making each number into a character that is a single byte.

What if I bitwise or it with 0x0000?

>>>mySock.sendto(bytes(65000 | 0x0000), addr)
5

Well, darn it! The closest thing I've come to is messing around with hex() and bytearray(). See below.

>>>hex(65000)
'0xfde8'
>>>mySock.sendto('\xfde8', addr)
3

Shouldn't that say 2 bytes? I'm not sure how this works. Also, when the number is less than 16384 I want to preserve the preceding 0's. So, for example, if the port number is 255 (0b0000000011111111) I want it to remain as a 2 byte data structure (0x00FF) rather than truncating down to 0xFF or 0b11111111.


Solution

  • If you want to send binary data, please use module struct. That will help you to encode the string and to make sure that you are using the proper endianness. For example:

    >>> import struct
    >>> struct.pack('!H', 65000)
    '\xfd\xe8'
    

    That's 65000 as an unsigned short, in network order (big endian)