4.3 Python Network Programming
4.3 Python Network Programming
4.3 Python Network Programming
To download packages from the PyPI repository, you can use several tools, but
in this section, we will explain how to use the pip command to do so. pip is the
official package installer that comes already installed when you install Python on
your local machine.
You can find all of the Python networking libraries in the Python PyPI
repository, such as requests (https://pypi.org/project/requests) and urllib (https://pyp
i.org/project/urllib3).
Installing packages with conda is just as easy as with pip—just run conda install
<package_name>; for example, conda install requests.
The conda repository is independent of the official Python repository and does
not find all of the Python packages that are in PyPI, but you will find all of the
Python networking libraries such as requests (https://anaconda.org/anaconda/requests),
urllib, and socket.
Virtualenv
virtualenv is a Python tool for creating virtual environments. To install it, you just
have to run pip install virtualenv. With this, you can start creating virtual
environments, for example, virtualenv ENV. Here, ENV is a directory that will be
installed in a virtual environment that includes a separate Python installation. For
more information, see the complete guide, which includes information on how to
activate the environments: https://virtualenv.pypa.io.
Pipenv
Pipenv is a relatively new tool that modernizes the way Python manages
dependencies, and includes a complete dependency resolver in the same way
conda does for handling virtual environments, locking files, and more. Pipenv is
an official Python program, so you just have to run pip install pipenv to install it.
You can find an excellent guide for Pipenv in English here: https://realpython.com/
pipenv-guide.
An introduction to libraries for
network programming with Python
Python provides modules for interfacing with protocols at different levels in the
network stack, and modules that support higher-layer protocols follow the
aforementioned principle by using the interfaces that are supplied by the lower-
level protocols.
Introduction to sockets
The socket module is Python's standard interface for the transport layer, and it
provides functions for interacting with TCP and UDP, as well as for looking up
hostnames through DNS. In this section, we will introduce you to this module.
We'll learn much more about this in Chapter 10, Programming with Sockets.
A socket is defined by the IP address of the machine, the port on which it listens,
and the protocol it uses. The types and functions that are needed to work with
sockets are in Python in the socket module.
The sockets can also be classified according to their family. We have Unix
sockets, such as socket.AF_UNIX, that were created before the conception of the
networks and are based on socket.AF_INET file, which are based on network
connections and sockets related to connections with IPv6, such as socket.AF_INET6.
Socket module in Python
To create a socket, the socket.socket() constructor is used, which can take the
family, type, and protocol as optional parameters. By default, the AF_INET family
and the SOCK_STREAM type are used.
bind(): With this method, we can define in which port our server will be
listening to connections
listen(backlog): This method makes the socket accept connections and accept
to start listening to connections
accept(): This method is used for accepting the following connection:
import socket
RFCs cover a wide range of standards, and TCP/IP is just one of these. They are
freely available on the IETF's website, which can be found at
www.ietf.org/rfc.html. Each RFC has a number; IPv4 is documented by RFC 791,
and other relevant RFCs will be mentioned as we progress throughout this book.
The most important IPs are defined by RFC, such as the IP protocol that's
detailed in RFC 791, FTP in RFC 959, or HTTP in RFC 2616.
You can use this service to search by RFC number or keyword. This can be
found here: https://www.rfc-editor.org/search/rfc_search.php.
In the following screenshot, we can see the result of searching for RFC number
2616 for the HTTP protocol:
Extracting RFC information
The IETF landing page for RFCs is http://www.rfc-editor.org/rfc/, and reading
through it tells us exactly what we want to know. We can access a text version of
an RFC using a URL of the form http://www.rfc-editor.org/rfc/rfc741.txt. The RFC num
ber in this case is 741. Therefore, we can get the text format of RFCs using HTTP.
At this point, we can build a Python script for downloading an RCF document
from IETF, and then display the information that's returned by the service. We'll
make it a Python script that just accepts an RFC number, downloads the RFC in
text format, and then prints it to stdout.
The main modules that we can find in Python to make HTTP requests are urllib
and requests, which work at a high level. We can also use the socket module if we
want to work at a low level.
Downloading an RFC with urllib
Now, we are going to write our Python script using the urllib module. For this,
create a text file called RFC_download_urllib.py:
#!/usr/bin/env python3
This is the output of the previous script, where we can see the RFC description
document:
First, we import our modules and check whether an RFC number has been
supplied on the command line. Then, we construct our URL by substituting the
supplied RFC number. Next, the main activity, the urlopen() call, will construct an
HTTP request for our URL, and then it will connect to the IETF web server and
download the RFC text. Next, we decode the text to Unicode, and finally we
print it out to the screen.
Downloading an RFC with requests
Now, are going to create the same script but, instead of using urllib, we are going
to use the requests module. For this, create a text file called
RFC_download_requests.py:
#!/usr/bin/env python3
We can simplify the previous script using the requests module. The main
difference with the requests module is that we use the get method for the request
and access the text property to get information about the specific RFC.
Downloading an RFC with the socket
module
Now, we are going to create the same script but, instead of using urllib or
requests, we are going to use the socket module for working at a low level. For
this, create a text file called RFC_download_socket.py:
#!/usr/bin/env python3
host = 'www.rfc-editor.org'
port = 80
sock = socket.create_connection((host, port))
req = req.format(rfcnum=rfc_number,host=host,port=port,version=sys.version_info[0])
sock.sendall(req.encode('ascii'))
rfc_bytes = bytearray()
while True:
buf = sock.recv(4096)
if not len(buf):
break
rfc_bytes += buf
rfc = rfc_bytes.decode('utf-8')
print(rfc)
The main difference here is that we are using a socket module instead of urllib or
requests. Socket is Python's interface for the operating system's TCP and UDP
Then, we piece together the server's response as it arrives in the while loop. Bytes
that are sent to us through a TCP socket are presented to our application in a
continuous stream. So, like any stream of unknown length, we have to read it
iteratively. The recv() call will return the empty string after the server sends all of
its data and closes the connection. Finally, we can use this as a condition for
breaking out and printing the response.