PICO W在Micropython环境下的socket.recv()等待耗时问题

PICO 35cm2022-09-02185 次点击1 人感谢
新近入手PICO W,在官方的Micropython环境下测试与上位机之间的TCP/IP数据通信,发现socket.recv()等待耗时(无论是阻塞模式下还是在非阻塞模式下)有问题:完成接收一个数据包耗时400ms~500ms,哪怕CPU提速到250MHz也无济于事,令人发指,难道是我使用的方法不对?!

如果采用缺省的阻塞模式:接收就一行 data=tcp.recv(128) , 系统就在此卡上400~500ms;

以下是采用非阻塞模式,10ms间隔检查 data=tcp.recv(128)的接收状况,直到接收完数据包结束,总耗时同时是400~500ms,但至少系统还能正常循环处理,不至于卡顿在那句接收上:

# TCP接收处理:TCP/IP=True
tcp.setblocking(0) # 设置非阻塞模式

try:
data=tcp.recv(128) # 一次最多接收128字节
TcpRecStr.append(data) # 拼接到接收数据串中
TCPIP=False # 接收完成:切断TCP连接(短连接模式)

except OSError: # 处理阻塞告警
TcpCount=TcpCount+1 # TCP阻塞计数++

if TcpCount>100:
# 非阻塞告警超过100*10mS,视作TCP连接中断
TCPIP=False # 出现TCP连接问题:切断TCP连接,重新连接


if TCPIP==False:
tcp.close() # 切断TCP连接
TcpCount=0 # TCP阻塞计数清0


玩编程到现在,还是头一回碰上网络TCP/IP数据交互居然比串口UART数据交互慢的情况。
收藏 ♥ 感谢
Spoony 小组长 2022-09-03 
pico w 还没有入手,竟然会有这种坑。。
不知道 C 语言框架会不会好很多
PICO 35cm 2022-09-03  ♥ 1
而在树莓派4B的python环境下,几乎同样的结构没有感觉到有时延(是否有阻塞都没考虑过),每秒收发100次是肯定有的:

# TCP发送处理:
try: # 进行TCP数据发送
conn.settimeout(0.5) # 设置TCP发送时限500mS
conn.sendall(temp.encode()) # Bytes流发送数据
except: # 如果TCP数据发送过程出错
conn.close() # 切断TCP连接
time.sleep(0.1) # 发送异常强制休眠100mS(释放系统资源)
continue # 进入下一循环

# 完成TCP数据发送

# TCP接收处理:最多接收256字节
try: # 启动TCP接收
conn.settimeout(0.5) # 设置TCP接收等待时限500mS
data=conn.recv(256) # 最多接收256个字节
except: # 如果TCP接收出错
conn.close() # 切断TCP连接
time.sleep(0.1) # 接收异常强制休眠100mS(释放系统资源)
continue # 进入下一循环

# 收到TCP数据
conn.close() # TCP短连接结束:立即切断TCP连接
PICO 35cm 2022-09-12 
反复捣腾PICO W一个多星期,总算有点眉目,记录一下,也算是给后来者避点坑:

硬件:PICO W,固件:官方MicorPython(rp2-pico-w-20220909-unstable-v1.19.1-389-g4903e48e3.uf2)

将PICO W作为客户端,以TCP短连接模式与服务器端进行数据交互,即在建立Wifi网络通信后,PICO W循环运行:
- 发起TCP连接
- 发送数据
- 接收应答
- 切断TCP连接

服务器端的常规流程:
- 侦听到连接请求后建立TCP连接
- 接收数据
- 发送应答
- 切断TCP连接

然而,交互过程出奇的慢,基本就是每秒2次数据交互:
Connect Start: 1182483
Connect OK: 1182584
Send Start: 1182585
Send OK: 1182585
Rec Start: 1182586
Rec OK: 1182900
Connect Close: 1182901

Connect Start: 1182955
Connect OK: 1183056
Send Start: 1183056
Send OK: 1183057
Rec Start: 1183057
Rec OK: 1183414
Connect Close: 1183415

Connect Start: 1183468
Connect OK: 1183569
Send Start: 1183570
Send OK: 1183571
Rec Start: 1183571
Rec OK: 1183926
Connect Close: 1183927

耗时大头:
建立TCP连接(阻塞模式):100mS左右
接收数据(非阻塞模式):350mS左右

真是奇了怪了,用Pi4B或Zero2W(Python环境),同样的客户端模式运行、同样的Wifi网络,至少实现每秒近百次的数据交互;


在服务器端软件的配合下,专门做了单发、单收测试,发现除了建立TCP连接仍然需要100mS左右(阻塞模式)绕不过去,其他都是mS级别耗时,极限情况下实现每秒9次数据发或收;

由此怀疑PICO W在MicorPython下TCP数据发送完转换到数据接收时有异常耗时问题,于是根据测试结果对服务器端软件的TCP数据接收、发送次序进行调整,即:
- 在侦听到连接请求建立TCP连接的同时启动一个75mS延时,延时结束后发送数据(不管数据接收情况)
- 正常接收数据
- 等收到客户端切断TCP连接信号后再切断本方TCP连接(不能主动切断本方TCP连接)

实现了在极限情况下每秒8次数据交互(过程总耗时110mS左右),但运行不是很稳定;

经过反复测试,最后确定:过程耗时110mS左右+间隔50mS的稳定运行循环,实现每秒6次的数据交互(应用的基本要求):
Connect Start: 1405163
Connect OK: 1405263
Send Start: 1405264
Send OK: 1405265
Rec Start: 1405265
Rec OK: 1405281
Connect Close: 1405282

Connect Start: 1405341
Connect OK: 1405442
Send Start: 1405443
Send OK: 1405443
Rec Start: 1405444
Rec OK: 1405455
Connect Close: 1405456

Connect Start: 1405509
Connect OK: 1405610
Send Start: 1405610
Send OK: 1405611
Rec Start: 1405612
Rec OK: 1405612
Connect Close: 1405613


接下去的连续运行测试中又出现几个问题:
1 在创建socket对象的语句前加上__del__(),解决连续运行期间该创建socket语句时不时出现报错的问题:

tcp.__del__()
tcp=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

2 连续运行一段时间后会出现TCP连接始终失败的问题:即tcp.connect((ServerIP,ServerPort))始终报错,但此时wifi连接又显示正常,status()值为3,没辙,只好切断当前Wifi连接,重新尝试连接Wifi;
但此时又出现另一个问题:重新连接上Wifi后的status()值始终为1,而不是正常的3,只有machine.reset()硬复位或断电再上电重启才能恢复正常。

研究了一通network库内容,在创建network对象的语句后加上了deinit(),问题解决:

wlan=network.WLAN(network.STA_IF)
wlan.deinit()
wlan.active(True)

3 涉及Wifi过程以及板载Led操作(PICO W改用Wifi芯片输出口,非原来Pin25)都只能在主核中运行,一旦利用 _thread.start_new_thread()函数将其加载到另外1核中,该核直接死锁无法运行。

幸亏PICO W是双核结构,这种TCP下connect()可直接阻塞100mS在单核结构里是无实用意义的,目前的设计是:
主核跑Wifi网络的应用,另1核跑需要ms级响应要求的流程;

4 在加了散热风扇的情况下,基本上连续运行测试10多个小时后2个核的进程会全部当掉,而此时显示的CPU温度并不高,基本就是35°上下,目前的解决办法看来只能是靠启动看门狗监测重启;


总体感觉:目前PICO W在新增的Wifi网络这块还不甚稳定,不知道这是MicroPython固有劣门?还是仅仅为官方MicorPython固件的Bug?

登录注册 后可回复。



GitHub