一、socketserver 模块简介
socketserver 是 Python 标准库中的一个高级模块,它的目标是简化很多样板代码,这些代码是创建网络客户端和服务器所必需的代码。这个模块中有创建好的各种各样的类,如下表所示。
模块中的类 | 描述 |
---|---|
BaseServer | 包含核心服务器功能和 mix-in 类的钩子,仅用于推导,这样不会创建这个类的实例,可以用 TCPServer 或 UDPServer 创建类的实例 |
TCPServer / UDPServer | 基础网络的同步服务器 |
UnixStreamServer / UnixDatagramServer | 基于文件的同步服务器 |
ForKingMixIn / ThreadingMinIn | 核心派出或线程功能;只用作 mix-in 类与一个服务器类配合实现一些异步性;不能直接实例化 |
ForKingTCPServer / ForkingUDPServer | ForKingMixIn 和 TCPServer / UDPServer 的组合 |
ThreadingTCPServer / ThreadingUDPServer | ThreadingMixIn 和 TCPServer / UDPServer 的组合 |
BaseRequestHandler | 包含处理服务请求的核心功能,仅用于推导,无法创建实例,可以使用 StreamRequestHandler 或 DatagramRequestHandler 创建类的实例 |
StreamRequestHandler / DatagramRequestHandler | 实现 TCP / UDP 服务器的处理器 |
通过 Python 网络编程一(CS 架构和 socket 模块)展示的基本 TCP 示例,我们将使用 socketserver 创建一个 TCP 服务器。你会发现它们之间存在明显的相似性,但是也应该看到我们如何处理一些繁琐的工作,于是你不必担心样板代码。这些代表了你能够编写的最简单的同步服务器。除了为你隐藏了实现细节之外,另一个不同之处是,我们现在使用类来编写应用程序。因为以面向对象的方式处理事务有助于组织数据,将功能放在逻辑正确的地方。你还会注意到,应用程序现在是事件驱动的,这意味着只有在系统中的事件发生时,它们才会工作。
事件包括消息的发送和接收。事实上,你会看到类定义只包括一个用来接收客户端消息的事件处理程序。所有其他的功能都来自使用的 socketserver 类。此外,GUI 编程也是事件驱动的。你会立即注意到它们的相似性,因为最后一行代码通常是一个服务器的无限循环,它等待并响应客户端的服务请求。它工作起来几乎与本章前面的基础 TCP 服务器中的无限 while 循环一样。
在原始服务器循环中,我们阻塞等待请求,当接收到请求时就对其提供服务,然后继续等待。在此处的服务器循环中,并非在服务器中创建代码,而是定义一个处理程序,这样当服务器接收到一个传入的请求时,服务器就可以调用你的函数。
二、使用 socketserver 创建 TCP 服务器
使用 TCPServer 创建 TCP 服务,将以下代码写入 tcp_ss.py 文件中:
from socketserver import TCPServer, StreamRequestHandler
import time
ADDR = ('', 1234)
BUFSIZ = 1024
# 创建 StreamRequestHandler 类的子类
class MyRequestHandler(StreamRequestHandler):
# 重写 handle 方法,该方法在父类中什么都不做
# 当客户端主动连接服务器成功后,自动运行此方法
def handle(self):
# client_address 属性的值为客户端的主机端口元组
print('... connected from {}'.format(self.client_address))
# request.recv 方法接收客户端发来的消息
data = self.request.recv(BUFSIZ)
# request.sendall 方法发送消息给客户端
self.request.sendall('[{}] {}'.format(
time.ctime(), data.decode()).encode())
def main():
# 创建 TCP 服务器并启动,该服务器为单线程设计,不可同时为两个客户端收发消息
# 该服务器每次连接客户端成功后,运行一次 handle 方法然后断开连接
# 也就是说,每次客户端的请求就是一次收发消息
# 连续请求需要客户端套接字不断重新创建
tcp_server = TCPServer(ADDR, MyRequestHandler)
print('等待客户端连接...')
try:
tcp_server.serve_forever() # 服务器永远等待客户端的连接
except KeyboardInterrupt:
tcp_server.server_close() # 关闭服务器套接字
print('\nClose')
exit()
if __name__ == '__main__':
main()
创建 TCP 客户端,仍然使用 socket 模块,将以下代码写入 tcp_sc.py 文件:
1 from socket import socket, AF_INET, SOCK_STREAM
2
3 ADDR = ('localhost', 1234)
4 BUFSIZ = 1024
5
6 # 这个循环不断运行下去
7 # 每次连接服务器,发送并接收消息,就是一次循环
8 # 循环结束时关闭客户端套接字,下次循环重新创建
9 while True:
10 tcp_client_sock = socket(AF_INET, SOCK_STREAM)
11 tcp_client_sock.connect(ADDR)
12 data = input('输入内容:')
13 if not data:
14 break
15 tcp_client_sock.send(data.encode())
16 data = tcp_client_sock.recv(BUFSIZ)
17 if not data:
18 break
19 print(data.decode())
20 tcp_client_sock.close()
网友评论