We can write a client that will wait for a particular network service forever or for a timeout. In this example, by default, we would like to check when a web server is up in localhost. If you specified some other remote host or port, that information will be used instead.
Listing 3.3 shows waiting for a remote network service, as follows:
#!/usr/bin/env python # Python Network Programming Cookbook, Second Edition -- Chapter - 3 # This program is optimized for Python 2.7.12 and Python 3.5.2. # It may run on any other version with/without modifications. import argparse import socket import errno from time import time as now DEFAULT_TIMEOUT = 120 DEFAULT_SERVER_HOST = 'localhost' DEFAULT_SERVER_PORT = 80 class NetServiceChecker(object): """ Wait for a network service to come online""" def __init__(self, host, port, timeout=DEFAULT_TIMEOUT): self.host = host self.port = port self.timeout = timeout self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) def end_wait(self): self.sock.close() def check(self): """ Check the service """ if self.timeout: end_time = now() + self.timeout while True: try: if self.timeout: next_timeout = end_time - now() if next_timeout < 0: return False else: print ("setting socket next timeout %ss"
%round(next_timeout)) self.sock.settimeout(next_timeout) self.sock.connect((self.host, self.port)) # handle exceptions except socket.timeout as err: if self.timeout: return False except socket.error as err: print ("Exception: %s" %err) else: # if all goes well self.end_wait() return True if __name__ == '__main__': parser = argparse.ArgumentParser(description='Wait for
Network Service') parser.add_argument('--host', action="store", dest="host",
default=DEFAULT_SERVER_HOST) parser.add_argument('--port', action="store", dest="port",
type=int, default=DEFAULT_SERVER_PORT) parser.add_argument('--timeout', action="store", dest="timeout",
type=int, default=DEFAULT_TIMEOUT) given_args = parser.parse_args() host, port, timeout = given_args.host, given_args.port,
given_args.timeout service_checker = NetServiceChecker(host, port, timeout=timeout) print ("Checking for network service %s:%s ..." %(host, port)) if service_checker.check(): print ("Service is available again!")
If a web server is running on your machine, this script will show the following output:
$ python 13_3_wait_for_remote_service.py Waiting for network service localhost:80 ... setting socket next timeout 120.0s Service is available again!
If you do not have a web server already running in your computer, make sure to install one such as Apache 2 web server:
$ sudo apt install apache2
Now, stop the Apache process:
$ sudo /etc/init.d/apache2 stop
It will print the below message while stopping the service.
[ ok ] Stopping apache2 (via systemctl): apache2.service.
Run this script, and start Apache again.
$ sudo /etc/init.d/apache2 start [ ok ] Starting apache2 (via systemctl): apache2.service.
The output pattern will be different for a different machine. On my machine, the following output pattern was found:
Exception: [Errno 103] Software caused connection abort setting socket next timeout 119.0s Exception: [Errno 111] Connection refused setting socket next timeout 119.0s Exception: [Errno 103] Software caused connection abort setting socket next timeout 119.0s Exception: [Errno 111] Connection refused setting socket next timeout 119.0s And finally when Apache2 is up again, the following log is printed: Service is available again!
The following screenshot shows the waiting for an active Apache web server process: