C:\...\Internet\Sockets> python echo-client.py learning-python.com Blue, no yellow!
Client received: b"Echo=>b'Blue,' at Sat Apr 24 07:19:55 2010"
Client received: b"Echo=>b'no' at Sat Apr 24 07:19:55 2010"
Client received: b"Echo=>b'yellow!' at Sat Apr 24 07:19:55 2010"
Now that we have a handle on the basic model, let’s move on to the tricky bits. This
server script is fairly straightforward as forking code goes, but a few words about the
library tools it employs are in order.
Forked processes and sockets
We met os.fork in Chapter 5, but recall that forked processes are essentially a copy of
the process that forks them, and so they inherit file and socket descriptors from their
parent process. As a result, the new child process that runs the handleClient function
has access to the connection socket created in the parent process. Really, this is why
the child process works at all—when conversing on the connected socket, it’s using
the same socket that parent’s accept call returns. Programs know they are in a forked
child process if the fork call returns 0; otherwise, the original parent process gets back
the new child’s ID.
Exiting from children
In earlier fork examples, child processes usually call one of the exec variants to start a
new program in the child process. Here, instead, the child process simply calls a func-
tion in the same program and exits with os._exit. It’s imperative to call os._exit here—
if we did not, each child would live on after handleClient returns, and compete for
accepting new client requests.
In fact, without the exit call, we’d wind up with as many perpetual server processes as
requests served—remove the exit call and do a ps shell command after running a few
clients, and you’ll see what I mean. With the call, only the single parent process listens
for new requests. os._exit is like sys.exit, but it exits the calling process immediately
without cleanup actions. It’s normally used only in child processes, and sys.exit is
used everywhere else.
Killing the zombies: Don’t fear the reaper!
Note, however, that it’s not quite enough to make sure that child processes exit and
die. On systems like Linux, though not on Cygwin, parents must also be sure to issue
a wait system call to remove the entries for dead child processes from the system’s
process table. If we don’t do this, the child processes will no longer run, but they will
consume an entry in the system process table. For long-running servers, these bogus
entries may become problematic.
It’s common to call such dead-but-listed child processes zombies: they continue to use
system resources even though they’ve already passed over to the great operating system
beyond. To clean up after child processes are gone, this server keeps a list,
Handling Multiple Clients | 807