React Native通过BLE NUS向树莓派发送Base64数据解码失败问题
问题解决:Nordic UART BLE传输拆包导致Base64解码失败
核心问题
React Native通过Nordic UART服务和树莓派GATT服务器通信时,retrieveHubConfig指令、Base64编码的JSON数据会被拆成100字符的小包传输,导致树莓派解码时出现填充错误、UTF-8无效字节、Base64字符数不符合规则等问题。
根本原因
Nordic UART的默认分包阈值通常设为100字符,而BLE传输本身是流式的,不会自动帮你拼接数据包,必须在应用层实现分包重组逻辑,不然只解码片段肯定会出错。
解决方案
两端配合处理:发送端给完整消息加结束标记,接收端先缓存拼接完整数据包,再解码处理。
1. React Native发送端修改
给每个要发送的完整消息加个结束标记(比如换行符\n),让接收端能识别出完整数据包:
// React Native发送函数示例 const sendDataToHub = async (data) => { // 字符串指令直接用,JSON先转Base64 let encodedData = typeof data === 'string' ? data : btoa(JSON.stringify(data)); // 加结束标记 encodedData += '\n'; // 走Nordic UART发送 await bleManager.writeCharacteristicForDevice( deviceId, NUS_SERVICE_UUID, NUS_TX_CHARACTERISTIC_UUID, encodedData ); }; // 发送指令示例 sendDataToHub('retrieveHubConfig'); // 发送JSON数据示例 sendDataToHub({ wifiSSID: "MyWiFi", password: "123456" });
2. 树莓派接收端修改
在接收回调里先缓存字节流,检测到结束标记后再取出完整消息解码:
import base64 import json # 全局缓存,存未拼接完的数据包 received_buffer = "" def handle_received_data(data): global received_buffer # 字节转字符串,统一用UTF-8编码 received_str = data.decode('utf-8') received_buffer += received_str # 循环处理所有已完成的数据包 while '\n' in received_buffer: # 拆分出完整消息和剩余缓存 full_msg, received_buffer = received_buffer.split('\n', 1) process_full_message(full_msg) def process_full_message(msg): try: # 判断是指令还是Base64 JSON if msg == 'retrieveHubConfig': # 执行读取.ini文件逻辑 print("收到读取配置指令") # 这里加你的.ini读取代码 else: # 解码Base64,开启校验确保格式正确 decoded_bytes = base64.b64decode(msg, validate=True) # 转JSON json_data = json.loads(decoded_bytes.decode('utf-8')) # 执行写入.ini逻辑 print("收到配置JSON:", json_data) # 这里加你的.ini写入代码 except base64.binascii.Error as e: print(f"Base64解码失败: {e}") except json.JSONDecodeError as e: print(f"JSON解析失败: {e}") except UnicodeDecodeError as e: print(f"UTF-8解码失败: {e}") # GATT接收回调里调用handle_received_data(根据你的框架调整) def on_characteristic_write_request(char, value, options): handle_received_data(value) return char.RESULT_SUCCESS
3. 额外优化:协商更大MTU
如果数据包比较大,连接成功后协商更大的MTU,减少分包次数:
React Native端协商MTU
// 设备连接成功后调用 await bleManager.requestMtu(deviceId, 512); // 最大支持512字节,看硬件能力
树莓派端开启MTU支持
用bluetoothctl配置:
bluetoothctl menu gatt set mtu 512 exit
对应报错的解决逻辑
- 填充错误/Base64字符数异常:之前只解码了片段,拼接成完整消息后字符数自然是4的倍数,不用手动补填充符。
- UTF-8无效字节:分包的字节可能不是完整的UTF-8字符,拼接成完整字符串后再解码就不会出问题。
内容的提问来源于stack exchange,提问作者Tycho Systems
相关产品推荐
相关产品推荐

