Something is ticking.

Python Threads and Sockets Example – DNS Server and Client

I’m too lazy to make a decent write-up for this code so I’m just going to post it. More information about threading and sockets can be found in the official documentation:
http://docs.python.org/library/threading.html
http://docs.python.org/library/socket.html
Code after the break

Server code (server.py)

import socket
import threading
import re
import signal
import sys

# This class represents the request handler thread
class RequestHandler(threading.Thread):
    # Each thread receives the socket and client address from accept()
    def __init__(self, (sock, addr)):
        self.sock = sock
        self.addr = addr

        threading.Thread.__init__(self)

    # This is where the magic happens
    def run(self):
        # Domain names are a maximum of 253 characters long
        raw_data = self.sock.recv(253)
        # Remove invalid characters
        domain_name = re.sub('[^a-zA-Z0-9\.\-]', '', raw_data)
        print self.getName() + ' looking up ' + domain_name

        # Here we will "try" to resolve the host and catch any exceptions (failed lookups)
        try:
            # Resolve the name
            ip = socket.gethostbyname(domain_name)
            print '  >> ' + ip
            # Send the IP back to the client
            self.sock.send(ip)
        except socket.gaierror, msg:
            # An exception was raised
            print 'Unable to resolve host ' + domain_name
            # Unknown host, send error message
            self.sock.send('Unable to resolve host ' + domain_name)

        # Close the client socket
        self.sock.close()
        self.sock = None

#
# Setup the server socket and threads list
#
server_sock = socket.socket()
# Setting this option avoids the TIME_WAIT state so that we can rebind faster
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(('127.0.0.1', 6052))
server_sock.listen(2)
threads = []

# Keyboard Interrupt handler and cleanup routine
def cleanup(*args):
    print 'Exiting'

    global server_sock
    global threads

    # Close the server socket
    server_sock.close()
    server_sock = None

    # Wait for all threads
    for t in threads:
        t.join()

    sys.exit(0)

# Catch some signals
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)

# The "main" loop
# Accepts connections and fires off threads
while True:
    rh = RequestHandler(server_sock.accept())
    rh.daemon = True
    rh.start()
    threads.append(rh)

# Execution never reaches here but this should be the last call
cleanup()

… and the client code (client.py)

import socket
import signal
import sys

# Keyboard Interrupt handler and cleanup routine
def cleanup(*args):
    global client_sock

    # Close the client socket
    client_sock.close()
    client_sock = None

    sys.exit(0)

# Catch some signals
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)

# Require one argument (host to be resolved)
if len(sys.argv) < 2:
    print 'Usage: python %s <domain name>' % sys.argv[0]
    sys.exit(0)

#
# Setup client socket and connect
#
client_sock = socket.socket()
client_sock.connect(('127.0.0.1', 6052))

# Send the domain name to the server
client_sock.send(sys.argv[1])
# Recv the response and print
ip = client_sock.recv(276)
print ip

# Finally, cleanup
cleanup()

Enjoy!

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.