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

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,提问作者이관우

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:00:01