Python Socket服务端发3条消息客户端仅收2条、后两条合并如何解决
问题原因
TCP是面向字节流的传输协议,没有内置的消息边界标识:
- 服务端多次调用
send发送的小包,可能被操作系统的Nagle算法合并为一个包发送,减少网络开销 - 客户端调用
recv时是从内核的TCP接收缓冲区读数据,单次recv可能拿到多次send合并后的内容,不会和服务端的send调用一一对应
你遇到的现象就是服务端的第二条、第三条消息被合并发送,客户端第二次recv就把这两条内容都读走了,第三次recv时所有数据已经读完,服务端又已经关闭连接,所以返回空字节。
解决方案
1. 临时测试方案:禁用Nagle算法
只适合本地测试用,生产环境不推荐,因为会增加网络小包数量降低传输效率。
在服务端accept拿到连接socket后添加一行配置即可:
c, addr = s.accept() # 新增以下行,禁用Nagle算法 c.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
2. 生产推荐方案:自定义消息边界
有三种常用的实现方式,可根据业务场景选择:
固定长度消息
约定所有消息的长度统一,客户端每次recv都读取对应长度的字节即可,优点是实现简单,缺点是灵活性差,浪费带宽。
分隔符拆分消息
你当前的每条消息末尾都带有逗号,可以直接用逗号作为消息分隔符,客户端维护接收缓冲区,每次把新收到的数据加入缓冲区,再按逗号拆分出完整消息:
import socket HOST = '192.168.1.54' PORT = 5000 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) buffer = b'' msg_count = 0 while msg_count < 3: data = s.recv(1024) if not data: break buffer += data # 按分隔符拆分消息 while b',' in buffer: msg, buffer = buffer.split(b',', 1) # 把分隔符加回来,和原来的消息格式一致 full_msg = msg + b',' print(full_msg) msg_count += 1
头部携带长度字段
在每条消息的头部固定位置存储本次消息的长度,客户端先读取固定长度的头部拿到消息长度,再读取对应长度的内容,是生产环境最通用的方案,不会出现分隔符和消息内容冲突的问题。
内容的提问来源于stack exchange,提问作者GGGGGG
相关产品推荐
相关产品推荐

