[Python编程(第4版)].(Programming.Python.4th.Edition).Mark.Lutz.文字版

(yzsuai) #1

request prevents the server from returning to the code that checks for new clients in a
timely manner, it won’t be able to keep up with all the requests, and some clients will
eventually be denied connections.


In real-world client/server programs, it’s far more typical to code a server so as to avoid
blocking new requests while handling a current client’s request. Perhaps the easiest
way to do so is to service each client’s request in parallel—in a new process, in a new
thread, or by manually switching (multiplexing) between clients in an event loop. This
isn’t a socket issue per se, and we already learned how to start processes and threads
in Chapter 5. But since these schemes are so typical of socket server programming, let’s
explore all three ways to handle client requests in parallel here.


Forking Servers


The script in Example 12-4 works like the original echo server, but instead forks a new
process to handle each new client connection. Because the handleClient function runs
in a new process, the dispatcher function can immediately resume its main loop in
order to detect and service a new incoming request.


Example 12-4. PP4E\Internet\Sockets\fork-server.py


"""
Server side: open a socket on a port, listen for a message from a client,
and send an echo reply; forks a process to handle each client connection;
child processes share parent's socket descriptors; fork is less portable
than threads--not yet on Windows, unless Cygwin or similar installed;
"""


import os, time, sys
from socket import * # get socket constructor and constants
myHost = '' # server machine, '' means local host
myPort = 50007 # listen on a non-reserved port number


sockobj = socket(AF_INET, SOCK_STREAM) # make a TCP socket object
sockobj.bind((myHost, myPort)) # bind it to server port number
sockobj.listen(5) # allow 5 pending connects


def now(): # current time on server
return time.ctime(time.time())


activeChildren = []
def reapChildren(): # reap any dead child processes
while activeChildren: # else may fill up system table
pid, stat = os.waitpid(0, os.WNOHANG) # don't hang if no child exited
if not pid: break
activeChildren.remove(pid)


def handleClient(connection): # child process: reply, exit
time.sleep(5) # simulate a blocking activity
while True: # read, write a client socket
data = connection.recv(1024) # till eof when socket closed
if not data: break


Handling Multiple Clients | 803
Free download pdf