socketserverA framework for network servers网络服务器框架

Source code: Lib/socketserver.py


The socketserver module simplifies the task of writing network servers.socketserver模块简化了编写网络服务器的任务。

There are four basic concrete server classes:有四个基本的具体服务器类:

classsocketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

This uses the internet TCP protocol, which provides for continuous streams of data between the client and server. 这使用互联网TCP协议,该协议提供客户端和服务器之间的连续数据流。If bind_and_activate is true, the constructor automatically attempts to invoke server_bind() and server_activate(). 如果bind_and_activatetrue,构造函数会自动尝试调用server_bind()server_activate()The other parameters are passed to the BaseServer base class.其他参数传递给BaseServer基类。

classsocketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

This uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit. 这使用数据报,这是离散的信息包,可能会无序到达或在传输过程中丢失。The parameters are the same as for TCPServer.参数与TCPServer相同。

classsocketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
classsocketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)

These more infrequently used classes are similar to the TCP and UDP classes, but use Unix domain sockets; they’re not available on non-Unix platforms. 这些更不常用的类类似于TCP和UDP类,但使用Unix域套接字;它们在非Unix平台上不可用。The parameters are the same as for TCPServer.参数与TCPServer相同。

These four classes process requests synchronously; each request must be completed before the next request can be started. 这四个类同步处理请求;在启动下一个请求之前,必须完成每个请求。This isn’t suitable if each request takes a long time to complete, because it requires a lot of computation, or because it returns a lot of data which the client is slow to process. 如果每个请求都需要很长时间才能完成,这是不合适的,因为它需要大量计算,或者因为它返回了大量客户端处理速度较慢的数据。The solution is to create a separate process or thread to handle each request; the ForkingMixIn and ThreadingMixIn mix-in classes can be used to support asynchronous behaviour.解决方案是创建一个单独的进程或线程来处理每个请求;类中的ForkingMixIn和ThreadingMixIn混合可以用于支持异步行为。

Creating a server requires several steps. 创建服务器需要几个步骤。First, you must create a request handler class by subclassing the BaseRequestHandler class and overriding its handle() method; this method will process incoming requests. 首先,必须通过子类化BaseRequestHandler类并覆盖其handle()方法来创建请求处理程序类;此方法将处理传入的请求。Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class. 其次,必须实例化其中一个服务器类,向其传递服务器地址和请求处理程序类。It is recommended to use the server in a with statement. 建议在with语句中使用服务器。Then call the handle_request() or serve_forever() method of the server object to process one or many requests. 然后调用服务器对象的handle_request()serve_forever()方法来处理一个或多个请求。Finally, call server_close() to close the socket (unless you used a with statement).最后,调用server_close()关闭套接字(除非使用with语句)。

When inheriting from ThreadingMixIn for threaded connection behavior, you should explicitly declare how you want your threads to behave on an abrupt shutdown. 当从ThreadingMixIn继承线程连接行为时,应明确声明希望线程在突然关闭时的行为。The ThreadingMixIn class defines an attribute daemon_threads, which indicates whether or not the server should wait for thread termination. ThreadingMixIn类定义了一个属性daemon_threads,它指示服务器是否应该等待线程终止。You should set the flag explicitly if you would like threads to behave autonomously; the default is False, meaning that Python will not exit until all threads created by ThreadingMixIn have exited.如果希望线程自主运行,则应显式设置标志;默认值为False,这意味着在ThreadingMixIn创建的所有线程退出之前,Python不会退出。

Server classes have the same external methods and attributes, no matter what network protocol they use.服务器类具有相同的外部方法和属性,无论它们使用什么网络协议。

Server Creation Notes服务器创建说明

There are five classes in an inheritance diagram, four of which represent synchronous servers of four types:继承图中有五个类,其中四个表示四种类型的同步服务器:

+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+

Note that UnixDatagramServer derives from UDPServer, not from UnixStreamServer — the only difference between an IP and a Unix stream server is the address family, which is simply repeated in both Unix server classes.请注意,UnixDatagramServer派生自UDPServer,而不是UnixStreamServer-IP和Unix流服务器之间的唯一区别是地址系列,这在两个Unix服务器类中简单重复。

classsocketserver.ForkingMixIn
classsocketserver.ThreadingMixIn

Forking and threading versions of each type of server can be created using these mix-in classes. 可以使用这些混合类创建每种类型服务器的分叉和线程版本。For instance, ThreadingUDPServer is created as follows:例如,ThreadingUDPServer的创建方式如下:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
pass

The mix-in class comes first, since it overrides a method defined in UDPServer. 首先是类中的混合,因为它覆盖了UDPServer中定义的方法。Setting the various attributes also changes the behavior of the underlying server mechanism.设置各种属性也会更改基础服务器机制的行为。

ForkingMixIn and the Forking classes mentioned below are only available on POSIX platforms that support fork().和下面提到的Forking类仅在支持fork()的POSIX平台上可用。

socketserver.ForkingMixIn.server_close() waits until all child processes complete, except if socketserver.ForkingMixIn.block_on_close attribute is false.等待所有子进程完成,除非socketserver.ForkingMixIn.block_on_close属性为false

socketserver.ThreadingMixIn.server_close() waits until all non-daemon threads complete, except if 等待所有非守护进程线程完成,除非socketserver.ThreadingMixIn.block_on_close attribute is false. 属性为falseUse daemonic threads by setting ThreadingMixIn.daemon_threads to True to not wait until threads complete.使用守护线程,方法是将ThreadingMixIn.daemon_threads设置为True,以便不等待线程完成。

Changed in version 3.7:版本3.7中更改: socketserver.ForkingMixIn.server_close() and socketserver.ThreadingMixIn.server_close() now waits until all child processes and non-daemonic threads complete. socketserver.ForkingMixIn.server_close()socketserver.ThreadingMixIn.server_close()Add a new socketserver.ForkingMixIn.block_on_close class attribute to opt-in for the pre-3.7 behaviour.添加一个新的socketserver.ForkingMixIn.block_on_close类属性来选择3.7之前的行为。

classsocketserver.ForkingTCPServer
classsocketserver.ForkingUDPServer
classsocketserver.ThreadingTCPServer
classsocketserver.ThreadingUDPServer

These classes are pre-defined using the mix-in classes.这些类是使用混合类预定义的。

To implement a service, you must derive a class from BaseRequestHandler and redefine its handle() method. 要实现服务,必须从BaseRequestHandler派生类并重新定义其handle()方法。You can then run various versions of the service by combining one of the server classes with your request handler class. 然后,您可以通过将其中一个服务器类与您的请求处理程序类相结合来运行各种版本的服务。The request handler class must be different for datagram or stream services. 数据报或流服务的请求处理程序类必须不同。This can be hidden by using the handler subclasses StreamRequestHandler or DatagramRequestHandler.这可以通过使用处理程序子类StreamRequestHandlerDatagramRequestHandler来隐藏。

Of course, you still have to use your head! 当然,你还得动动脑筋!For instance, it makes no sense to use a forking server if the service contains state in memory that can be modified by different requests, since the modifications in the child process would never reach the initial state kept in the parent process and passed to each child. 例如,如果服务在内存中包含可由不同请求修改的状态,那么使用分叉服务器是没有意义的,因为子进程中的修改永远不会达到保存在父进程中并传递给每个子进程的初始状态。In this case, you can use a threading server, but you will probably have to use locks to protect the integrity of the shared data.在这种情况下,可以使用线程服务器,但可能必须使用锁来保护共享数据的完整性。

On the other hand, if you are building an HTTP server where all data is stored externally (for instance, in the file system), a synchronous class will essentially render the service “deaf” while one request is being handled – which may be for a very long time if a client is slow to receive all the data it has requested. 另一方面,如果您正在构建一个HTTP服务器,其中所有数据都存储在外部(例如,在文件系统中),那么在处理一个请求时,同步类实际上会使服务“失聪”——如果客户端接收所请求的所有数据的速度较慢,这可能会持续很长时间。Here a threading or forking server is appropriate.在这里,线程或分叉服务器是合适的。

In some cases, it may be appropriate to process part of a request synchronously, but to finish processing in a forked child depending on the request data. 在某些情况下,可以同步处理部分请求,但根据请求数据在分叉子级中完成处理。This can be implemented by using a synchronous server and doing an explicit fork in the request handler class handle() method.这可以通过使用同步服务器并在请求处理程序类handle()方法中执行显式fork来实现。

Another approach to handling multiple simultaneous requests in an environment that supports neither threads nor fork() (or where these are too expensive or inappropriate for the service) is to maintain an explicit table of partially finished requests and to use selectors to decide which request to work on next (or whether to handle a new incoming request). 在既不支持线程也不支持fork()的环境中处理多个同时请求的另一种方法是维护一个包含部分完成的请求的显式表,并使用选择器决定下一个处理哪个请求(或是否处理新的传入请求)。This is particularly important for stream services where each client can potentially be connected for a long time (if threads or subprocesses cannot be used). 对于流服务来说,这一点尤其重要,因为在流服务中,每个客户端都可能长时间连接(如果无法使用线程或子流程)。See asyncore for another way to manage this.请参阅asyncore以了解管理此问题的另一种方法。

Server Objects对象

classsocketserver.BaseServer(server_address, RequestHandlerClass)

This is the superclass of all Server objects in the module. 这是模块中所有Server对象的超类。It defines the interface, given below, but does not implement most of the methods, which is done in subclasses. 它定义了接口,如下所示,但没有实现大多数方法,这是在子类中完成的。The two parameters are stored in the respective server_address and RequestHandlerClass attributes.这两个参数分别存储在server_addressRequestHandlerClass属性中。

fileno()

Return an integer file descriptor for the socket on which the server is listening. 返回服务器正在侦听的套接字的整数文件描述符。This function is most commonly passed to selectors, to allow monitoring multiple servers in the same process.此函数通常传递给selectors,以允许监视同一进程中的多个服务器。

handle_request()

Process a single request. 处理单个请求。This function calls the following methods in order: get_request(), verify_request(), and process_request(). 此函数按顺序调用以下方法:get_request()verify_request()process_request()If the user-provided handle() method of the handler class raises an exception, the server’s handle_error() method will be called. 如果用户提供的处理程序类的handle()方法引发异常,将调用服务器的handle_error()方法。If no request is received within timeout seconds, handle_timeout() will be called and handle_request() will return.如果在timeout秒内没有收到请求,将调用handle_timeout()并返回handle_request()

serve_forever(poll_interval=0.5)

Handle requests until an explicit shutdown() request. 处理请求,直到显式shutdown()请求。Poll for shutdown every poll_interval seconds. 每隔poll_interval秒轮询关机。Ignores the timeout attribute. 忽略timeout属性。It also calls service_actions(), which may be used by a subclass or mixin to provide actions specific to a given service. 它还调用service_actions(),子类或mixin可以使用它来提供特定于给定服务的操作。For example, the ForkingMixIn class uses service_actions() to clean up zombie child processes.例如,ForkingMixIn类使用service_actions()清理僵尸子进程。

Changed in version 3.3:版本3.3中更改: Added service_actions call to the serve_forever method.serve_forever方法添加了service_actions调用。

service_actions()

This is called in the serve_forever() loop. 这在serve_forever()循环中调用。This method can be overridden by subclasses or mixin classes to perform actions specific to a given service, such as cleanup actions.这个方法可以被子类或mixin类覆盖,以执行特定于给定服务的操作,例如清理操作。

New in version 3.3.版本3.3中新增。

shutdown()

Tell the serve_forever() loop to stop and wait until it does. 告诉serve_forever()循环停止并等待,直到停止为止。shutdown() must be called while serve_forever() is running in a different thread otherwise it will deadlock.必须在serve_forever()在不同线程中运行时调用,否则它将死锁。

server_close()

Clean up the server. 清理服务器。May be overridden.可能会被覆盖。

address_family

The family of protocols to which the server’s socket belongs. 服务器套接字所属的协议系列。Common examples are socket.AF_INET and socket.AF_UNIX.常见示例有socket.AF_INETsocket.AF_UNIX

RequestHandlerClass

The user-provided request handler class; an instance of this class is created for each request.用户提供的请求处理程序类;为每个请求创建一个此类的实例。

server_address

The address on which the server is listening. 服务器正在侦听的地址。The format of addresses varies depending on the protocol family; see the documentation for the socket module for details. 地址的格式因协议系列而异;有关详细信息,请参阅socket模块的文档。For internet protocols, this is a tuple containing a string giving the address, and an integer port number: ('127.0.0.1', 80), for example.例如,对于互联网协议,这是一个元组,包含一个给出地址的字符串和一个整数端口号:('127.0.0.1', 80)

socket

The socket object on which the server will listen for incoming requests.服务器将侦听传入请求的套接字对象。

The server classes support the following class variables:服务器类支持以下类变量:

allow_reuse_address

Whether the server will allow the reuse of an address. 服务器是否允许重复使用地址。This defaults to False, and can be set in subclasses to change the policy.这默认为False,可以在子类中设置以更改策略。

request_queue_size

The size of the request queue. 请求队列的大小。If it takes a long time to process a single request, any requests that arrive while the server is busy are placed into a queue, up to request_queue_size requests. 如果处理单个请求需要很长时间,那么在服务器繁忙时到达的任何请求都会被放入队列,最多可达request_queue_size请求。Once the queue is full, further requests from clients will get a “Connection denied” error. 一旦队列已满,来自客户端的进一步请求将收到“Connection denied”错误。The default value is usually 5, but this can be overridden by subclasses.默认值通常为5,但这可以被子类覆盖。

socket_type

The type of socket used by the server; socket.SOCK_STREAM and socket.SOCK_DGRAM are two common values.服务器使用的套接字类型;socket.SOCK_STREAMsocket.SOCK_DGRAM是两个常见值。

timeout

Timeout duration, measured in seconds, or None if no timeout is desired. 超时持续时间,以秒为单位,如果不需要超时,则为NoneIf handle_request() receives no incoming requests within the timeout period, the handle_timeout() method is called.如果handle_request()在超时时间内没有收到传入请求,则调用handle_timeout()方法。

There are various server methods that can be overridden by subclasses of base server classes like TCPServer; these methods aren’t useful to external users of the server object.有多种服务器方法可以被基本服务器类(如TCPServer)的子类覆盖;这些方法对服务器对象的外部用户没有用处。

finish_request(request, client_address)

Actually processes the request by instantiating RequestHandlerClass and calling its handle() method.实际上,通过实例化RequestHandlerClass并调用其handle()方法来处理请求。

get_request()

Must accept a request from the socket, and return a 2-tuple containing the new socket object to be used to communicate with the client, and the client’s address.必须接受来自套接字的请求,并返回一个2元组,其中包含用于与客户机通信的套接字对象和客户机地址。

handle_error(request, client_address)

This function is called if the handle() method of a RequestHandlerClass instance raises an exception. RequestHandlerClass实例的handle()方法引发异常,则调用此函数。The default action is to print the traceback to standard error and continue handling further requests.默认操作是打印标准错误的回溯并继续处理进一步的请求。

Changed in version 3.6:版本3.6中更改: Now only called for exceptions derived from the Exception class.现在只调用从Exception类派生的异常。

handle_timeout()

This function is called when the timeout attribute has been set to a value other than None and the timeout period has passed with no requests being received. timeout属性设置为非None的值并且超时时间已过且未收到任何请求时,将调用此函数。The default action for forking servers is to collect the status of any child processes that have exited, while in threading servers this method does nothing.分叉服务器的默认操作是集合已退出的所有子进程的状态,而在线程服务器中,此方法不执行任何操作。

process_request(request, client_address)

Calls finish_request() to create an instance of the RequestHandlerClass. 调用finish_request()创建RequestHandlerClass的实例。If desired, this function can create a new process or thread to handle the request; the ForkingMixIn and ThreadingMixIn classes do this.如果需要,这个函数可以创建一个新的进程或线程来处理请求;ForkingMixIn and ThreadingMixInThreadingMixIn类可以做到这一点。

server_activate()

Called by the server’s constructor to activate the server. 由服务器的构造函数调用以激活服务器。The default behavior for a TCP server just invokes listen() on the server’s socket. TCP服务器的默认行为只是在服务器的套接字上调用listen()May be overridden.可能会被覆盖。

server_bind()

Called by the server’s constructor to bind the socket to the desired address. 由服务器的构造函数调用以将套接字绑定到所需地址。May be overridden.可能会被覆盖。

verify_request(request, client_address)

Must return a Boolean value; if the value is True, the request will be processed, and if it’s False, the request will be denied. 必须返回布尔值;如果值为True,则将处理请求,如果值为False,则拒绝请求。This function can be overridden to implement access controls for a server. 可以重写此函数以实现服务器的访问控制。The default implementation always returns True.默认实现始终返回True

Changed in version 3.6:版本3.6中更改: Support for the context manager protocol was added. 添加了对上下文管理器协议的支持。Exiting the context manager is equivalent to calling server_close().退出上下文管理器相当于调用server_close()

Request Handler Objects请求处理程序对象

classsocketserver.BaseRequestHandler

This is the superclass of all request handler objects. 这是所有请求处理程序对象的超类。It defines the interface, given below. 它定义了接口,如下所示。A concrete request handler subclass must define a new handle() method, and can override any of the other methods. 具体的请求处理程序子类必须定义一个新的handle()方法,并且可以覆盖任何其他方法。A new instance of the subclass is created for each request.为每个请求创建子类的新实例。

setup()

Called before the handle() method to perform any initialization actions required. handle()方法之前调用,以执行所需的任何初始化操作。The default implementation does nothing.默认实现不执行任何操作。

handle()

This function must do all the work required to service a request. 此功能必须完成服务请求所需的所有工作。The default implementation does nothing. 默认实现不执行任何操作。Several instance attributes are available to it; the request is available as self.request; the client address as self.client_address; and the server instance as self.server, in case it needs access to per-server information.它可以使用多个实例属性;请求可以作为self.request使用;客户地址为self.client_address;服务器实例作为self.server,以防它需要访问每台服务器的信息。

The type of self.request is different for datagram or stream services. 数据报或流服务的self.request类型不同。For stream services, self.request is a socket object; for datagram services, self.request is a pair of string and socket.对于流服务,self.request是一个套接字对象;对于数据报服务,self.request是一对字符串和套接字。

finish()

Called after the handle() method to perform any clean-up actions required. handle()方法之后调用,以执行所需的任何清理操作。The default implementation does nothing. 默认实现不执行任何操作。If setup() raises an exception, this function will not be called.如果setup()引发异常,则不会调用此函数。

classsocketserver.StreamRequestHandler
classsocketserver.DatagramRequestHandler

These BaseRequestHandler subclasses override the setup() and finish() methods, and provide self.rfile and self.wfile attributes. 这些BaseRequestHandler子类覆盖setup()finish()方法,并提供self.rfileself.wfile属性。The self.rfile and self.wfile attributes can be read or written, respectively, to get the request data or return data to the client.可以分别读取或写入self.rfileself.wfile属性,以获取请求数据或将数据返回给客户机。

The rfile attributes of both classes support the io.BufferedIOBase readable interface, and DatagramRequestHandler.wfile supports the io.BufferedIOBase writable interface.这两个类的rfile属性都支持io.BufferedIOBase可读接口,DatagramRequestHandler.wfile支持io.BufferedIOBase可写接口。

Changed in version 3.6:版本3.6中更改: StreamRequestHandler.wfile also supports the io.BufferedIOBase writable interface.还支持io.BufferedIOBase可写接口。

Examples示例

socketserver.TCPServer Example示例

This is the server side:这是服务器端:

import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.

It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""

def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())

if __name__ == "__main__":
HOST, PORT = "localhost", 9999

# Create the server, binding to localhost on port 9999
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()

An alternative request handler class that makes use of streams (file-like objects that simplify communication by providing the standard file interface):使用流的替代请求处理程序类(通过提供标准文件接口简化通信的类似文件的对象):

class MyTCPHandler(socketserver.StreamRequestHandler):
def handle(self):
# self.rfile is a file-like object created by the handler;
# we can now use e.g. readline() instead of raw recv() calls
self.data = self.rfile.readline().strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# Likewise, self.wfile is a file-like object used to write back
# to the client
self.wfile.write(self.data.upper())

The difference is that the readline() call in the second handler will call recv() multiple times until it encounters a newline character, while the single recv() call in the first handler will just return what has been sent from the client in one sendall() call.区别在于,第二个处理程序中的readline()调用将多次调用recv(),直到遇到换行符,而第一个处理程序的单个recv()调用只会在一次sendall()调用中返回客户端发送的内容。

This is the client side:这是客户端:

import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])

# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(bytes(data + "\n", "utf-8"))

# Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")

print("Sent: {}".format(data))
print("Received: {}".format(received))

The output of the example should look something like this:示例的输出应如下所示:

Server:服务器:

$ python TCPServer.py
127.0.0.1 wrote:
b'hello world with TCP'
127.0.0.1 wrote:
b'python is nice'

Client:客户:

$ python TCPClient.py hello world with TCP
Sent: hello world with TCP
Received: HELLO WORLD WITH TCP
$ python TCPClient.py python is nice
Sent: python is nice
Received: PYTHON IS NICE

socketserver.UDPServer Example示例

This is the server side:这是服务器端:

import socketserver
class MyUDPHandler(socketserver.BaseRequestHandler):
"""
This class works similar to the TCP handler class, except that
self.request consists of a pair of data and client socket, and since
there is no connection the client address must be given explicitly
when sending data back via sendto().
"""

def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print("{} wrote:".format(self.client_address[0]))
print(data)
socket.sendto(data.upper(), self.client_address)

if __name__ == "__main__":
HOST, PORT = "localhost", 9999
with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
server.serve_forever()

This is the client side:这是客户端:

import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])

# SOCK_DGRAM is the socket type to use for UDP sockets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# As you can see, there is no connect() call; UDP has no connections.
# Instead, data is directly sent to the recipient via sendto().
sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8")

print("Sent: {}".format(data))
print("Received: {}".format(received))

The output of the example should look exactly like for the TCP server example.该示例的输出应该与TCP服务器示例的输出完全相同。

Asynchronous Mixins异步混音器

To build asynchronous handlers, use the ThreadingMixIn and ForkingMixIn classes.若要构建异步处理程序,请使用ThreadingMixInForkingMixIn类。

An example for the ThreadingMixIn class:ThreadingMixIn类的示例:

import socket
import threading
import socketserver
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass

def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))

if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0

server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
ip, port = server.server_address

# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)

client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")

server.shutdown()

The output of the example should look something like this:示例的输出应如下所示:

$ python ThreadedTCPServer.py
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3

The ForkingMixIn class is used in the same way, except that the server will spawn a new process for each request. ForkingMixIn类的使用方式相同,只是服务器将为每个请求生成一个新进程。Available only on POSIX platforms that support fork().仅在支持fork()的POSIX平台上可用。