ESP32与Python TCP服务器双向通信:服务端下发JSON问题求助
ESP32与Python TCP服务端双向通信可落地修正方案
现存核心问题定位
- Python服务端时序逻辑错误:原代码将发送数据的代码放在
recv循环退出之后,只有当ESP32完全断开连接时才会触发发送动作,此时ESP32已经处于断连流程中,根本无法接收数据;同时原代码构造的JSON字符串存在语法错误,{"accel","gyro","time":1}缺失键值对冒号,不属于合法JSON格式;s.listen(0)将全连接队列长度设为0,易导致连接被内核直接丢弃。 - ESP32端接收逻辑错误:发送完上报数据后立刻读取服务端返回,未考虑TCP传输的网络延迟,此时服务端返回的报文还未到达ESP32缓存区,直接读取会拿到空值;代码中重复定义
char c变量,存在编译错误;仅读1个字符就停止接收,无法读完整段JSON报文,读完后立刻执行断连操作,没有给传输留足缓冲时间。
修正后的Python TCP服务端代码
import socket s = socket.socket() # 监听地址保持不变,将全连接队列长度设为1,满足单设备通信需求 s.bind(('192.168.1.11', 5000)) s.listen(1) while True: client, addr = s.accept() print(f"收到来自{addr}的新连接") # 构造合法的JSON指令字符串 send_cmd = bytes('{"accel":0.1,"gyro":0.2,"time":123456}', "utf-8") while True: content = client.recv(32) if len(content) == 0: # 仅当ESP32主动触发断连时才退出接收循环 break else: print(f"收到ESP32上报数据: {content}") # 调整发送时机:收到ESP32上报数据后立刻发送指令,不等断连 client.send(send_cmd) # 给连接设置2秒超时,等待ESP32处理完接收后再关闭连接 client.settimeout(2) try: while client.recv(1024): pass except socket.timeout: pass print("Closing connection") client.close()
修正后的ESP32(Arduino框架)代码
#include <WiFi.h> #include <WiFiClient.h> const char* ssid = "#########"; const char* password = "######"; const uint16_t port = 5000; const char * host = "192.168.1.11"; // 定义全局WiFiClient实例,无需每次循环新建对象 WiFiClient client; void setup() { Serial.begin(115200); delay(2000); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("WiFi连接中..."); } Serial.print("WiFi已连接,设备IP: "); Serial.println(WiFi.localIP()); } void loop() { // 检测连接状态,自动重连 if (!client.connected()) { Serial.println("连接已断开,尝试重新连接服务端..."); if (!client.connect(host, port)) { Serial.println("连接服务端失败,1秒后重试"); delay(1000); return; } Serial.println("已成功连接到服务端!"); } // 发送ESP32端的上报数据 client.print("Hello from ESP32!"); // 留100ms网络传输延迟,避免立刻读缓存拿空值 delay(100); String recv_buffer = ""; // 设置5秒接收超时,避免无限等待 uint32_t recv_start_time = millis(); while (millis() - recv_start_time < 5000) { if (client.available()) { char c = client.read(); recv_buffer += c; // 读到JSON结束的右大括号时判定一帧接收完成 if (c == '}') { break; } } } if (recv_buffer.length() > 0) { Serial.print("收到服务端JSON指令: "); Serial.println(recv_buffer); } // 留2秒缓冲时间,等数据完全传输完成再断连 delay(2000); Serial.println("断开当前连接..."); client.stop(); delay(10000); }
落地验证注意事项
- 确保ESP32和运行Python服务端的设备处于同一个局域网,且Python端防火墙已放行5000端口的入站规则,否则会出现ESP32能发数据但收不到返回的情况
- 发送的JSON字符串必须保证语法合法,缺失冒号、多写逗号的格式错误会直接导致ESP32端解析失败
- TCP属于流式传输协议,本身没有固定报文边界,必须通过自定义结束标识(比如JSON的右大括号)判断一帧接收完成,不能指望单次读取就能拿到完整报文
内容的提问来源于stack exchange,提问作者Senuda Jayalath
相关产品推荐
相关产品推荐

