树莓派与电脑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
相关产品推荐
相关产品推荐

