09.11.2016 Views

Foundations of Python Network Programming 978-1-4302-3004-5

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

CHAPTER 7 ■ SERVER ARCHITECTURE<br />

several child processes (and it is rumored to also have an undocumented ThreadPool), that mechanism<br />

seems focused on distributing work from the master thread rather than on accepting different client<br />

connections from a common listening socket. So my last example in this chapter will be built atop the<br />

modest SocketServer module in the <strong>Python</strong> Standard Library.<br />

The SocketServer module was written a decade ago, which is probably obvious in the way it uses<br />

multiclassing and mix-ins—today, we would be more likely to use dependency injection and pass in the<br />

threading or forking engine as an argument during instantiation. But the arrangement works well<br />

enough; in Listing 7–10, you can see how small our multi-threaded server becomes when it takes<br />

advantage <strong>of</strong> this framework. (There is also a ForkingMixIn that you can use if you want it to spawn<br />

several processes—at least on a POSIX system.)<br />

Listing 7–10. Using the Standard Library Socket Server<br />

#!/usr/bin/env python<br />

# <strong>Foundations</strong> <strong>of</strong> <strong>Python</strong> <strong>Network</strong> <strong>Programming</strong> - Chapter 7 - server_SocketServer.py<br />

# Answering Launcelot requests with a SocketServer.<br />

from SocketServer import ThreadingMixIn, TCPServer, BaseRequestHandler<br />

import launcelot, server_simple, socket<br />

class MyHandler(BaseRequestHandler):<br />

» def handle(self):<br />

» » server_simple.handle_client(self.request)<br />

class MyServer(ThreadingMixIn, TCPServer):<br />

» allow_reuse_address = 1<br />

» # address_family = socket.AF_INET6 # if you need IPv6<br />

server = MyServer(('', launcelot.PORT), MyHandler)<br />

server.serve_forever()<br />

Note that this framework takes the opposite tack to the server that we built by hand in the previous<br />

section. Whereas our earlier example created the workers up front so that they were all sharing the same<br />

listening socket, the SocketServer does all <strong>of</strong> its listening in the main thread and creates one worker each<br />

time accept() returns a new client socket. This means that each request will run a bit more slowly, since<br />

the client has to wait for the process or thread to be created before it can receive its first answer; and this<br />

is evident in Figure 7–5, where the volume <strong>of</strong> requests answered runs a bit lower than it did in Figure 7–4.<br />

A disadvantage <strong>of</strong> the SocketServer classes, so far as I can see, is that there is nothing to stop a<br />

sudden flood <strong>of</strong> client connections from convincing the server to spin up an equal number <strong>of</strong> threads or<br />

processes—and if that number is large, then your computer might well slow to a crawl or run out <strong>of</strong><br />

resources rather than respond constructively to the demand. Another advantage to the design <strong>of</strong><br />

Listing 7–9, then, is that it chooses ahead <strong>of</strong> time how many simultaneous requests can usefully be<br />

underway, and leaves additional clients waiting for an accept() on their connections before they can<br />

start contributing to the load on the server.<br />

121

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!