让我来详细讲解一下“利用Python中SocketServer 实现客户端与服务器间非阻塞通信”的完整攻略。
1. 前置知识
在学习和掌握 SocketServer 实现非阻塞通信的过程中,你需要掌握以下几个基础概念:
- socket:套接字,用于实现网络通信的API;
- TCP/IP协议:TCP是一种面向连接的,可靠的,基于流的传输协议,而IP则是一种无连接的,不可靠的,面向分组的协议;
- select/poll/epoll模型:用于实现非阻塞I/O的模型,select是对文件描述符的轮询,poll基于select做了修改,epoll是Linux特有的一种I/O复用模型。
2. 实现过程
接下来,我们就来具体介绍一下 SocketServer 实现非阻塞通信的过程。
2.1 创建服务器
首先,我们需要创建一个服务器,并指定一个IP地址和端口号来进行监听:
import SocketServer
class MyTCPHandler(SocketServer.StreamRequestHandler):
def handle(self):
data = self.rfile.readline().strip()
self.wfile.write('Hello, ' + data)
if __name__ == "__main__":
HOST, PORT = "localhost", 8000
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
在上述代码中,我们创建了一个 MyTCPHandler 类,用于处理客户端连接和交互流程,其中 handle() 方法用于接收客户端发送的数据,并通过 wfile 属性将数据写回客户端。
2.2 实现非阻塞服务
接下来,我们需要将服务器设置为非阻塞模式,实现数据的异步发送和接收。为此,我们需要使用 Python 标准库中的 select 模块来实现:
import select
if __name__ == "__main__":
HOST, PORT = "localhost", 8000
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.socket.setblocking(0)
inputs = [server.socket]
outputs = []
while inputs:
readable, _, _ = select.select(inputs, outputs, inputs)
for s in readable:
if s is server.socket:
conn, addr = s.accept()
conn.setblocking(0)
inputs.append(conn)
else:
data = s.recv(1024)
if data:
outputs.append(s)
else:
inputs.remove(s)
s.close()
for s in outputs:
s.send('Welcome, you are connected')
outputs.remove(s)
在上述代码中:
server.socket.setblocking(0)
将服务器设置为非阻塞模式;inputs = [server.socket]
开始监听服务端连接和客户端数据;readable, _, _ = select.select(inputs, outputs, inputs)
获取可读取的列表;if s is server.socket:
如果是服务端Socket,说明有新的客户端接入,此时需要将该客户端 Socket 设置为非阻塞模式,并将该 Socket 添加到 inputs 列表中,以便我们进行数据监听;data = s.recv(1024)
如果是客户端 Socket,则需要尝试接收客户端发送的数据;outputs.append(s)
如果客户端发送的数据不为空,则将该 Socket 添加到 outputs 列表中,说明这个客户端有数据需要发送;outputs.remove(s)
如果数据发送完成,则将该 Socket 从 outputs 列表中删除。
通过上述代码的实现,我们就可以使用 SocketServer 实现客户端与服务器间的非阻塞通信了!
2.3 示例说明
接下来,我将通过两个示例来说明 SocketServer 实现非阻塞通信的过程。
示例一
这个示例将演示如何使用 SocketServer 创建一个非阻塞服务,当客户端连接时,服务端将向客户端发送一条“欢迎”消息,客户端再向服务端发送一条消息,服务端再次向客户端发送一条“感谢”的消息。
import SocketServer
import select
class MyTCPHandler(SocketServer.StreamRequestHandler):
def handle(self):
data = self.rfile.readline().strip()
print('客户端{}:{}连接了'.format(self.client_address[0], self.client_address[1]))
inputs = [self.request]
outputs = []
while inputs:
readable, _, _ = select.select(inputs, outputs, inputs)
for s in readable:
if s is self.request:
data = self.request.recv(1024)
if data:
print('收到来自客户端{}:{}的信息:{}'.format(self.client_address[0], self.client_address[1], data.strip()))
outputs.append(s)
else:
print('客户端{}:{}已经断开'.format(self.client_address[0], self.client_address[1]))
inputs.remove(s)
s.close()
for s in outputs:
self.request.sendall('感谢你的信息'.encode())
outputs.remove(s)
print('客户端{}:{}离开了'.format(self.client_address[0], self.client_address[1]))
if __name__ == "__main__":
HOST, PORT = "localhost", 8000
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.socket.setblocking(0)
server.serve_forever()
示例二
这个示例将演示如何使用 SocketServer 创建一个 HTTP 服务器,并实现异步的处理请求。当有客户端请求时,服务端将返回一个响应头和一个Hello的响应体。
import SocketServer
import select
import time
class MyHTTPHandler(SocketServer.StreamRequestHandler):
def handle(self):
print('处理请求...')
data = self.rfile.readline().strip()
words = data.decode().split(' ')
print(words[0], words[1])
while True:
try:
line = self.rfile.readline()
if not line.strip():
break
except socket.timeout:
print('客户端超时,连接中断')
return
print('header完成')
inputs = [self.request]
outputs = []
while inputs:
readable, _, _ = select.select(inputs, outputs, inputs)
for s in readable:
if s is self.request:
data = self.request.recv(1024)
if data:
outputs.append(s)
else:
print('客户端{}:{}已经断开'.format(self.client_address[0], self.client_address[1]))
inputs.remove(s)
s.close()
for s in outputs:
response = 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello'
self.request.sendall(response.encode())
outputs.remove(s)
if __name__ == "__main__":
HOST, PORT = "localhost", 8000
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyHTTPHandler)
server.socket.setblocking(0)
server.serve_forever()
通过这两个示例,我们可以看到,在实现 SocketServer 非阻塞通信的过程中,我们需要通过 select 来对 inputs(服务端)和 outputs(客户端)进行监听,从而实现异步的数据通信。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:利用Python中SocketServer 实现客户端与服务器间非阻塞通信 - Python技术站