Python脚本接收暂停信号后无法立即终止Telnet流传输
我之前也碰到过类似的TCP流传输延迟暂停的问题,结合你的场景,大概率是内核发送缓冲区积压或者Python的阻塞I/O未响应信号导致的,咱们一步步拆解解决:
核心原因
当你发送SIGTSTP(也就是Ctrl+Z)信号时,进程会被标记为暂停状态,但如果此时脚本正处于阻塞式网络I/O操作中,或者内核TCP发送缓冲区里还有未发完的数据,内核会继续把缓冲区的内容发送完毕,才会真正暂停进程——这就是你看到几十秒延迟的根源。
具体解决办法
1. 给网络套接字设置超时,打破阻塞
在你的Python脚本里,给用于传输GCode的TCP套接字添加超时配置,这样信号到来时,阻塞的send/recv操作会更快被中断:
import socket # 创建套接字后立即设置超时 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(1) # 设置1秒超时,可根据你的流传输速度调整 s.connect(("192.168.3.222", <你的端口号>))
添加超时后,即使进程收到SIGTSTP,阻塞的I/O操作最多1秒就会抛出socket.timeout异常,你可以在异常处理里捕获它,然后立即暂停发送逻辑。
2. 捕获SIGTSTP信号,主动控制传输开关
在脚本里注册信号处理函数,当收到SIGTSTP时,直接切换传输状态为暂停,不再读取新的GCode行或发送数据:
import signal import time paused = False def handle_tstp(signum, frame): global paused paused = not paused if paused: print("脚本已暂停,执行fg/bg后将恢复传输") else: print("脚本已恢复GCode流传输") # 注册SIGTSTP信号处理 signal.signal(signal.SIGTSTP, handle_tstp) # 核心发送逻辑示例 with open("/path/to/file.gcode", 'r') as f: for line in f: # 暂停时循环等待,直到恢复 while paused: time.sleep(0.1) # 发送GCode行 s.send(line.encode().strip()) # 可选:等待设备确认,避免缓冲区过度积压 # resp = s.recv(1024)
这个方法能让你按下Ctrl+Z时立即停止读取和发送新的GCode,已经在缓冲区的少量数据会被内核发送完,但不会出现几十秒的延迟。
3. 调整TCP发送缓冲区大小(可选优化)
如果内核缓冲区积压严重,可以在脚本里缩小套接字的发送缓冲区,减少暂停时的残留数据量:
# 设置发送缓冲区为4KB,可根据实际情况调整 s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 4096)
注意:这个值不能超过系统的net.core.wmem_max限制,你可以用sysctl net.core.wmem_max命令查看当前系统的最大值。
验证方法
修改完脚本后,你可以用tcpdump再次测试效果:
tcpdump -i any host 192.168.3.222 and port <你的端口号>
按下Ctrl+Z后,应该只会看到少量残留数据包发送,之后就会立即停止,不会再有长达几十秒的延迟。
内容的提问来源于stack exchange,提问作者user3290570

