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

树莓派与电脑Socket传输JSON文件时更新报错的问题排查

树莓派与电脑间JSON文件传输的拼接错误问题

我在树莓派和电脑之间用socket模块传输JSON数据,将JSON转为字符串发送,接收后转成字典再写入JSON文件。但在while循环更新文件时出现语法错误,错误显示两个字典内容被拼接在一起(比如{'locx': '10',...}{'locx': '15',...})。我怀疑是刷新速度不足导致新数据追加到旧数据上,想确认这个判断是否正确,或者寻求其他传输方式、优化更新速度的方法。

电脑端接收代码

import socket
import json
import time
import ast

listensocket = socket.socket() #Creates an instance of socket
Port = 8000 #Port to host server on
maxConnections = 5

IP = '192.168.31.220'#socket.gethostname() IP address of local machine

listensocket.bind(('',Port))

#Starts server
listensocket.listen(maxConnections)
print("Server started at " + str(IP) + " on port " + str(Port))

#Accepts the incoming connection
(clientsocket, address) = listensocket.accept()
print("New connection made!")

dic=[]

while True:
    message = clientsocket.recv(1024).decode() #Gets the incoming message
    time.sleep(0.1)
    #message=json.loads(message)
    dictionary = ast.literal_eval(message)
    print(dictionary)
    with open("veri.json","w") as f:
        json.dump(dictionary,f)

问题原因分析

你的判断方向正确,核心问题是TCP是流式协议,recv(1024)无法保证每次都完整接收一个独立的JSON数据包:

  • 当树莓派发送速度较快时,多个JSON数据包可能被合并传输,一次recv会拿到多个拼接的JSON字符串,导致ast.literal_eval解析失败。
  • 也可能出现一次recv只拿到半个JSON字符串的情况,同样触发解析错误。
    time.sleep(0.1)只是临时缓解,无法从根本解决流式传输的粘包/分包问题。

解决方案

1. 给JSON数据包加分隔符(最简单可行方案)

在树莓派端发送每个JSON字符串时,末尾添加特殊分隔符(比如\n换行符);电脑端接收时缓存数据,直到遇到分隔符再解析完整的JSON内容。

修改后的电脑端代码:

import socket
import json

listensocket = socket.socket()
Port = 8000
maxConnections = 5
IP = '192.168.31.220'

listensocket.bind(('', Port))
listensocket.listen(maxConnections)
print(f"Server started at {IP} on port {Port}")

(clientsocket, address) = listensocket.accept()
print("New connection made!")

# 用于缓存不完整的接收数据
buffer = ""

while True:
    chunk = clientsocket.recv(1024).decode()
    if not chunk:
        break  # 连接断开时退出循环
    
    buffer += chunk
    # 按分隔符拆分,处理所有完整的JSON数据
    while '\n' in buffer:
        json_str, buffer = buffer.split('\n', 1)
        try:
            # 用json.loads替代ast.literal_eval,更安全且适配标准JSON格式
            dictionary = json.loads(json_str)
            print(dictionary)
            with open("veri.json", "w") as f:
                json.dump(dictionary, f)
        except json.JSONDecodeError as e:
            print(f"JSON解析失败: {e}")
            buffer = ""  # 清空错误缓存,避免影响后续解析

树莓派端发送时需添加换行符:

# 树莓派端发送示例片段
import json
import socket

client_socket = socket.socket()
client_socket.connect(('192.168.31.220', 8000))

# 构造数据并发送,末尾加换行符作为分隔
data = {"locx": "10", "locy": "20"}
client_socket.send((json.dumps(data) + '\n').encode())

2. 固定数据包长度(适合数据长度稳定的场景)

发送JSON前先传输数据包的长度(比如用4字节整数表示),电脑端先接收长度值,再接收对应长度的字节数据,确保每次拿到完整的JSON内容。

3. 使用上层协议简化开发

如果不想手动处理粘包问题,可以直接使用更成熟的协议:

  • HTTP:树莓派用requests库发送POST请求,电脑端搭建Flask/Django服务接收JSON。
  • MQTT:适合物联网场景,自带消息边界处理,可借助EMQX等中间件实现可靠传输。

额外优化建议

  • 替换ast.literal_eval为json.loads:json.loads是专门处理JSON的工具,比ast.literal_eval更安全、性能更好,且能兼容标准JSON格式。
  • 移除time.sleep(0.1):解决粘包问题后,延迟会降低传输效率,无保留必要。

内容的提问来源于stack exchange,提问作者Muhammed Tahsin Taşgın

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:33:19