Python中基于有状态TCP Socket的高层通信方案问询
Python 有状态TCP通信的高层封装方案
针对你遇到的TCP粘包、手动处理分片和结束条件繁琐的问题,Python提供了几种高层封装方案,既能保留TCP的有状态长连接特性,又能轻松处理多行文本、多部分二进制数据:
1. 内置socketserver模块:同步TCP服务端封装
socketserver是Python标准库对socket的同步封装,支持TCP长连接,可自定义请求处理逻辑来解析行分隔数据或自定义协议。
示例(服务端):
from socketserver import TCPServer, StreamRequestHandler class Handler(StreamRequestHandler): def handle(self): # 按行读取数据,自动处理粘包中换行分隔的内容 while True: line = self.rfile.readline() if not line: break line = line.strip() if line == b"OK, finished": break print(f"Received: {line}") if __name__ == "__main__": with TCPServer(("localhost", 9999), Handler) as server: server.serve_forever()
客户端可以保持原有发送逻辑,StreamRequestHandler的rfile/wfile类文件对象会自动处理缓冲区和数据分片。
2. asyncio流:异步TCP通信封装
如果需要异步处理,asyncio的StreamReader/StreamWriter是更现代的选择,支持按行读取、二进制数据传输,同时保留TCP长连接状态。
示例(服务端):
import asyncio async def handle_client(reader, writer): while True: # 按行读取,自动处理换行分隔的内容 data = await reader.readline() if not data: break data = data.strip() if data == b"OK, finished": break print(f"Received: {data}") writer.close() await writer.wait_closed() async def main(): server = await asyncio.start_server(handle_client, "localhost", 9999) async with server: await server.serve_forever() asyncio.run(main())
客户端同样可以用asyncio的流来发送数据,无需手动处理分片。
3. 长度前缀协议:处理多部分二进制数据
如果需要传输任意格式的二进制数据(不一定是行分隔),可以用长度前缀的方式定义简单协议:先发送数据的长度(用固定字节数的整数表示),再发送实际数据,这样接收端可以准确拆分数据包。
示例(客户端发送):
import struct def send_data(conn, data): # 用struct打包数据长度(4字节无符号整数) length = struct.pack('!I', len(data)) conn.sendall(length + data) # 发送多行数据 for i in range(10): send_data(connection, f"{i} and some other data\n".encode()) # 发送结束标记 send_data(connection, b"OK, finished")
示例(服务端接收):
import struct def recv_data(conn): # 先读取4字节的长度 length_data = conn.recv(4) if not length_data: return None length = struct.unpack('!I', length_data)[0] # 读取对应长度的数据 return conn.recv(length) while True: data = recv_data(clientsocket) if not data or data == b"OK, finished": break print(data)
这种方式完全避免粘包问题,适合传输复杂的多部分二进制数据。
4. 序列化工具:Python对象直接传输
如果仅在Python服务端和客户端之间通信,可以用pickle或json序列化数据,发送时先序列化,接收后反序列化,自动处理数据边界:
pickle支持几乎所有Python对象,但仅和可信客户端通信(存在安全风险)json更安全,支持跨语言,但只能序列化基本类型
示例(客户端):
import pickle # 发送数据 for i in range(10): data = pickle.dumps(f"{i} and some other data\n") connection.sendall(data) # 发送结束标记 connection.sendall(pickle.dumps("OK, finished"))
示例(服务端):
import pickle import io # 用BytesIO缓冲数据,处理分片 buffer = io.BytesIO() while True: chunk = clientsocket.recv(16384) if not chunk: break buffer.write(chunk) buffer.seek(0) try: while True: data = pickle.load(buffer) if data == "OK, finished": break print(data) except EOFError: # 未接收完一个完整的序列化对象,重置缓冲区位置 buffer.seek(buffer.tell()) continue break
以上所有方案都基于TCP长连接,保留了有状态特性,无需使用无状态的HTTP服务。
内容的提问来源于stack exchange,提问作者Basj
相关产品推荐
相关产品推荐

