socketserver
— 网络服务器框架
¶
源代码: Lib/socketserver.py
socketserver
模块简化编写网络服务器的任务。
有 4 个基本具体服务器类:
socketserver.
TCPServer
(
server_address
,
RequestHandlerClass
,
bind_and_activate=True
)
¶
这使用 Internet TCP 协议,在客户端和服务器之间提供连续数据流。若
bind_and_activate
为 True,构造函数自动试图援引
server_bind()
and
server_activate()
。其它参数被传递给
BaseServer
基类。
socketserver.
UDPServer
(
server_address
,
RequestHandlerClass
,
bind_and_activate=True
)
¶
这使用是离散信息数据包 (可能乱序到达或在传输过程中丢失) 的数据报。参数如同
TCPServer
.
socketserver.
UnixStreamServer
(
server_address
,
RequestHandlerClass
,
bind_and_activate=True
)
¶
socketserver.
UnixDatagramServer
(
server_address
,
RequestHandlerClass
,
bind_and_activate=True
)
¶
这些不常用类类似于 TCP 和 UDP 类,但使用 Unix 域套接字;它们不可用于非 Unix 平台。参数如同
TCPServer
.
这 4 个类处理请求
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.
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. 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. Then call the
handle_request()
or
serve_forever()
method of the server object to process one or many requests. Finally, call
server_close()
to close the socket (unless you used a
with
statement).
When inheriting from
ThreadingMixIn
for threaded connection behavior, you should explicitly declare how you want your threads to behave on an abrupt shutdown. The
ThreadingMixIn
class defines an attribute
daemon_threads
, which indicates whether or not the server should wait for thread termination. 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.
Server classes have the same external methods and attributes, no matter what network protocol they use.
在继承简图中有 5 个类,其中 4 个表示 4 种类型的同步服务器:
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
注意,
UnixDatagramServer
派生自
UDPServer
,不是来自
UnixStreamServer
— IP 和 Unix 流服务器之间的唯一差异是地址族,在两个 Unix 服务器类中简单重复。
socketserver.
ForkingMixIn
¶
socketserver.
ThreadingMixIn
¶
可以使用这些混合类为每种服务器类型创建分叉和线程化版本。例如,
ThreadingUDPServer
的创建如下:
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
pass
混合类首先出现,由于它覆盖的方法定义在
UDPServer
。设置各种属性也会改变底层服务器机制的行为。
ForkingMixIn
和下文提及的分叉类只可用于 POSIX (便携式操作系统接口) 平台支持
fork()
.
socketserver.ForkingMixIn.server_close()
等待直到所有子级进程完成,除了若
socketserver.ForkingMixIn.block_on_close
属性为 False。
socketserver.ThreadingMixIn.server_close()
等待直到所有非守护程序线程完成,除了若
socketserver.ThreadingMixIn.block_on_close
属性为 False。使用守护程序线程通过设置
ThreadingMixIn.daemon_threads
to
True
不等待直到线程完成。
3.7 版改变:
socketserver.ForkingMixIn.server_close()
and
socketserver.ThreadingMixIn.server_close()
现在等待直到所有子级进程和非守护程序线程完成。添加新的
socketserver.ForkingMixIn.block_on_close
类属性以选择加入 3.7 之前的行为。
socketserver.
ForkingTCPServer
¶
socketserver.
ForkingUDPServer
¶
socketserver.
ThreadingTCPServer
¶
socketserver.
ThreadingUDPServer
¶
这些类是使用混合类预定义的。
要实现服务,必须派生类从
BaseRequestHandler
and redefine its
handle()
method. 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
.
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. 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()
方法。
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). 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.
socketserver.
BaseServer
(
server_address
,
RequestHandlerClass
)
¶
这是模块中所有服务器对象的超类。它定义下文给出的接口,但不实现大多数在子类中完成的方法。2 参数存放在各自的
server_address
and
RequestHandlerClass
属性。
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.
handle_request
(
)
¶
Process a single request. This function calls the following methods in order:
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. If no request is received within
timeout
seconds,
handle_timeout()
will be called and
handle_request()
will return.
serve_forever
(
poll_interval=0.5
)
¶
Handle requests until an explicit
shutdown()
request. Poll for shutdown every
poll_interval
seconds. Ignores the
timeout
attribute. It also calls
service_actions()
, which may be used by a subclass or mixin to provide actions specific to a given service. For example, the
ForkingMixIn
class uses
service_actions()
to clean up zombie child processes.
3.3 版改变:
添加
service_actions
call to the
serve_forever
方法。
service_actions
(
)
¶
This is called in the
serve_forever()
loop. This method can be overridden by subclasses or mixin classes to perform actions specific to a given service, such as cleanup actions.
3.3 版新增。
shutdown
(
)
¶
告诉
serve_forever()
loop to stop and wait until it does.
shutdown()
must be called while
serve_forever()
is running in a different thread otherwise it will deadlock.
server_close
(
)
¶
清理服务器。可能被覆盖。
address_family
¶
The family of protocols to which the server’s socket belongs. Common examples are
socket.AF_INET
and
socket.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. For Internet protocols, this is a tuple containing a string giving the address, and an integer port number:
('127.0.0.1', 80)
,例如。
socket
¶
The socket object on which the server will listen for incoming requests.
服务器类支持下列类变量:
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.
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. Once the queue is full, further requests from clients will get a “Connection denied” error. The default value is usually 5, but this can be overridden by subclasses.
socket_type
¶
由服务器使用的套接字类型;
socket.SOCK_STREAM
and
socket.SOCK_DGRAM
是 2 常见值。
timeout
¶
Timeout duration, measured in seconds, or
None
if no timeout is desired. If
handle_request()
receives no incoming requests within the timeout period, the
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.
finish_request
(
request
,
client_address
)
¶
Actually processes the request by instantiating
RequestHandlerClass
and calling its
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.
handle_error
(
request
,
client_address
)
¶
此函数被调用若
handle()
方法的
RequestHandlerClass
实例引发异常。默认动作是将回溯打印到标准错误并继续处理进一步请求。
3.6 版改变:
现在仅被调用异常派生自
Exception
类。
handle_timeout
(
)
¶
此函数被调用当
timeout
attribute has been set to a value other than
None
and the timeout period has passed with no requests being received. 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
)
¶
调用
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.
server_bind
(
)
¶
被调用通过服务器的构造函数将套接字绑定到期望地址。可能被覆盖。
verify_request
(
request
,
client_address
)
¶
必须返回布尔值;若值为
True
,请求将被处理,和若它为
False
,请求将被拒绝。可以覆盖此函数以实现对服务器的访问控制。默认实现始终返回
True
.
3.6 版改变:
支持
上下文管理器
协议被添加。退出上下文管理器相当于调用
server_close()
.
socketserver.
BaseRequestHandler
¶
这是所有请求处理程序对象的超类。它定义了接口,下文给出。具体请求处理程序子类必须定义新的
handle()
方法,且可以覆盖任何其它方法。为每个请求创建新的子类实例。
setup
(
)
¶
Called before the
handle()
method to perform any initialization actions required. 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.
The type of
self.request
is different for datagram or stream services. For stream services,
self.request
是套接字对象;对于数据报服务,
self.request
is a pair of string and socket.
socketserver.
StreamRequestHandler
¶
socketserver.
DatagramRequestHandler
¶
这些
BaseRequestHandler
子类覆盖
setup()
and
finish()
方法,和提供
self.rfile
and
self.wfile
属性。
self.rfile
and
self.wfile
attributes can be read or written, respectively, to get the request data or return data to the client.
rfile
属性的 2 类支持
io.BufferedIOBase
可读接口,和
DatagramRequestHandler.wfile
支持
io.BufferedIOBase
可写接口。
3.6 版改变:
StreamRequestHandler.wfile
还支持
io.BufferedIOBase
可写接口。
socketserver.TCPServer
范例
¶
这是服务器侧:
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()
利用流的替代请求处理程序类 (通过提供标准文件接口简化通信的像文件对象):
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())
差异是
readline()
在第 2 个处理程序中的调用将调用
recv()
多次直到遇到换行符,而单个
recv()
在第 1 个处理程序中的调用将仅仅返回从客户端发送的内容在某一
sendall()
调用。
这是客户端侧:
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))
范例输出内容看起来应该像这样:
服务器:
$ python TCPServer.py
127.0.0.1 wrote:
b'hello world with TCP'
127.0.0.1 wrote:
b'python is nice'
客户端:
$ 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
范例
¶
这是服务器侧:
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()
这是客户端侧:
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))
范例输出看起来应该准确像 TCP 服务器范例。
要构建异步处理程序,使用
ThreadingMixIn
and
ForkingMixIn
类。
范例对于
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()
范例输出内容看起来应该像这样:
$ 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
ForkingMixIn
类使用方式相同,除服务器会为每个请求卵生新的进程外。只可用于 POSIX (便携式操作系统接口) 平台支持
fork()
.