Foundations of Python Network Programming

(WallPaper) #1
Chapter 2 ■ UDp

21

if name == 'main':
choices = {'client': client, 'server': server}
parser = argparse.ArgumentParser(description='Send and receive UDP locally')
parser.add_argument('role', choices=choices, help='which role to play')
parser.add_argument('-p', metavar='PORT', type=int, default=1060,
help='UDP port (default 1060)')
args = parser.parse_args()
function = choices[args.role]
function(args.p)


You should be able to run this script right on your own computer, even if you are not currently in the range of a
network, because both the server and the client use only the localhost IP address, which should be available whether
you are connected to a real network or not. Try starting the server first.


$ python udp_local.py server
Listening at ('127.0.0.1', 1060)


After printing this line of output, the server waits for an incoming message.
In the source code, you can see that it took three steps for the server to get up and running.
It first created a plain socket with the socket() call. This new socket is not yet bound to an IP address or port
number, is not yet connected to anything, and will raise an exception if you attempt to use it to communicate.
However, the socket is, at least, marked as being of a particular type: its family is AF_INET, the Internet family of
protocols, and it is of the SOCK_DGRAM datagram type, which means it will use UDP on an IP network. Note that the
term datagram (and not packet) is the official term for an application-level block of transmitted data because the
operating system networking stack does not guarantee that a single packet on the wire will actually represent a single
datagram. (See the following section, where I do insist on a one-to-one correspondence between datagrams and
packets so that you can measure the maximum transmission unit [MTU].)
Next, this simple server uses the bind() command to request a UDP network address, which you can see is a
simple Python tuple combining a str IP address (a hostname, you will see later, is also acceptable) and an int UDP
port number. This step could fail with an exception if another program is already using that UDP port and the server
script cannot obtain it. Try running another copy of the server—you will see that it complains as follows:


$ python udp_local.py server
Traceback (most recent call last):
...
OSError: [Errno 98] Address already in use


Of course, there is a small chance that you received this exception the first time you ran the server because UDP
port 1060 is already in use on your machine. It happens that I found myself in a bit of a bind when choosing the port
number for this first example. It had to be above 1023, of course, or you could not have run the script without being
a system administrator—and, while I do like my little example scripts, I really do not want to encourage anyone to
run them as the system administrator! I could have let the operating system choose the port number (as I did for the
client, as you will see in a moment), had the server print it out, and then made you type it into the client as one of its
command-line arguments. However, then I would not have gotten to show you the syntax for asking for a particular
port number yourself. Finally, I considered using a port from the high-numbered “ephemeral” range previously
described, but those are precisely the ports that might randomly already be in use by some other application on your
machine, such as your web browser or SSH client.

Free download pdf