Network Computing is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Python Network Programming: Handling Socket Errors

In any networking application, it’s common that one end will be trying to connect, while the other fails to respond due to a problem like a networking media failure. Fortunately, the Python socket library has an elegant method of handing these errors via the socket.error exceptions. Find out how to use them here.

How to do it

Let’s create a few try-except code blocks and put one potential error type in each block. In order to get a user input, the argparse module can be used. This module is more powerful than simply parsing command-line arguments using sys.argv. In the try-except blocks, put typical socket operations, for example, create a socket object, connect to a server, send data, and wait for a reply.

The following recipe illustrates the concepts in a few lines of code.

Listing 1.7 shows socket_errors as follows:

#!/usr/bin/env python

# Python Network Programming Cookbook -- Chapter – 1

# This program is optimized for Python 2.7. It may run on any  

# other Python version with/without modifications.

 

import sys

import socket

import argparse

 

def main():

    # setup argument parsing

    parser = argparse.ArgumentParser(description='Socket Error Examples')

    parser.add_argument('--host', action="store", dest="host", required=False)

    parser.add_argument('--port', action="store", dest="port", type=int, required=False)

    parser.add_argument('--file', action="store", dest="file", required=False)

    given_args = parser.parse_args()

    host = given_args.host

    port = given_args.port

    filename = given_args.file

 

    # First try-except block -- create socket

    try:

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    except socket.error, e:

        print "Error creating socket: %s" % e

        sys.exit(1)

 

    # Second try-except block -- connect to given host/port

    try:

        s.connect((host, port))

    except socket.gaierror, e:

        print "Address-related error connecting to server: %s" % e

        sys.exit(1)

    except socket.error, e:

        print "Connection error: %s" % e

        sys.exit(1)

 

    # Third try-except block -- sending data

    try:

        s.sendall("GET %s HTTP/1.0\r\n\r\n" % filename)

    except socket.error, e:

        print "Error sending data: %s" % e

        sys.exit(1)

 

    while 1:

        # Fourth tr-except block -- waiting to receive data from remote host

        try:

            buf = s.recv(2048)

        except socket.error, e:

            print "Error receiving data: %s" % e

            sys.exit(1)

        if not len(buf):

            break

        # write the received data

        sys.stdout.write(buf)

 

if __name__ == '__main__':

    main()

How it works

In Python, passing command-line arguments to a script and parsing them in the script can be done using the argparse module. This is available in Python 2.7. For earlier versions of Python, this module is available separately in Python Package Index (PyPI). You can install this via easy_install or pip.

In this recipe, three arguments are set up: a hostname, port number, and filename. The usage of this script is as follows:

$ python 1_7_socket_errors.py –host=<HOST> --port=<PORT> --file=<FILE>

 

If you try with a non-existent host, this script will print an address error as follows:

$ python 1_7_socket_errors.py --host=www.pytgo.org --port=8080 --file=1_7_socket_errors.py

 

Address-related error connecting to server: [Errno -5] No address associated with hostname

If there is no service on a specific port and if you try to connect to that port, then this will throw a connection timeout error as follows:

$ python 1_7_socket_errors.py --host=www.python.org --port=8080 --file=1_7_socket_errors.py

 

This will return the following error since the host, www.python.org, is not listening on port 8080:

Connection error: [Errno 110] Connection timed out

However, if you send an arbitrary request to a correct request to a correct port, the error may not be caught in the application level. For example, running the following script returns no error, but the HTML output tells us what's wrong with this script:

$ python 1_7_socket_errors.py --host=www.python.org --port=80 --file=1_7_socket_errors.py

 

HTTP/1.1 404 Not found

Server: Varnish

Retry-After: 0

content-type: text/html

Content-Length: 77

Accept-Ranges: bytes

Date: Thu, 20 Feb 2014 12:14:01 GMT

Via: 1.1 varnish

Age: 0

Connection: close

 

<html>

<head>

<title> </title>

</head>

<body>

unknown domain: </body></html>

In this example, four try-except blocks have been used. All blocks use socket.error except for the second one, which uses socket.gaierror. This is used for address-related errors. There are two other types of exceptions: socket.herror is used for legacy C API, and if you use the settimeout() method in a socket, socket.timeout will be raised when a timeout occurs on that socket.


This quick tip was taken from "Python Network Programming Cookbook" published by Packt. Network Computing readers can pick it up for free by clicking

here (which will automatically add the eBook to your cart) or by using the code RGPNPC50 at the checkout. The code expires Oct. 23, 2016. From October 10-16 you can save 50% on more Python ebooks by joining Packt for Python Week.