You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:40:15