Pygame双人联机游戏跨设备射击JSONDecodeError问题求助
问题解决方案
核心原因
你遇到的问题本质是TCP流式传输的粘包/拆包问题:TCP没有消息边界,当多段数据连续发送时,接收端可能一次性收到多个数据的拼接内容,或者单次只收到部分数据,导致json或pickle无法正确解析。移动功能正常只是巧合——移动数据量小,刚好能单次完整传输,而射击数据可能体积更大、发送更频繁,触发了粘包。
可行解决方法
1. 给数据添加长度前缀(最可靠方案)
发送数据前先传递固定字节数的长度信息,接收端先读取长度,再精准读取对应字节数的完整数据,彻底解决粘包问题。
发送端代码(支持json/pickle)
import struct import json # 替换成 import pickle 即可切换序列化方式 def send_packed_data(sock, data): # 序列化数据 serialized = json.dumps(data).encode('utf-8') # pickle的话用 pickle.dumps(data) # 把数据长度打包成4字节大端格式 length_header = struct.pack('!I', len(serialized)) # 先发送长度,再发送完整数据 sock.sendall(length_header) sock.sendall(serialized)
接收端代码
import struct import json # 对应发送端的序列化方式 def recv_packed_data(sock): # 先读取4字节的长度头部 length_data = sock.recv(4) if not length_data: return None # 连接断开 data_length = struct.unpack('!I', length_data)[0] # 按长度读取完整数据 received_data = b'' while len(received_data) < data_length: chunk = sock.recv(min(data_length - len(received_data), 4096)) if not chunk: return None received_data += chunk # 反序列化 return json.loads(received_data.decode('utf-8')) # pickle用 pickle.loads(received_data)
2. 使用分隔符标记消息边界(适合简单场景)
给每个序列化后的消息添加唯一分隔符(比如###END###),接收端持续接收数据直到匹配到分隔符,再截取有效内容解析。注意:分隔符不能出现在正常数据中,否则会误判。
发送端示例
import json def send_delimiter_data(sock, data): serialized = json.dumps(data).encode('utf-8') sock.sendall(serialized + b'###END###')
接收端示例
import json def recv_delimiter_data(sock): buffer = b'' while b'###END###' not in buffer: chunk = sock.recv(4096) if not chunk: return None buffer += chunk # 拆分有效数据和分隔符 raw_data = buffer.split(b'###END###')[0] # 保留缓冲区剩余内容(处理粘包) buffer = buffer[len(raw_data) + len(b'###END###'):] return json.loads(raw_data.decode('utf-8'))
3. 排查射击数据的特殊性
确认射击数据是否包含无法被序列化的内容:比如直接传递Pygame的Surface、Rect等对象(json/pickle都无法直接序列化这类对象)。必须把射击数据转换成基础数据类型(字典、列表、数字、字符串)再传输,比如把射击坐标打包成{"x": 100, "y": 200, "player_id": 1}这种结构。
内容的提问来源于stack exchange,提问作者이관우
相关产品推荐
相关产品推荐

