使用Paramiko远程执行树莓派包嗅探脚本时如何不阻塞主程序且可后续终止
问题根本原因
paramiko的exec_command是同步阻塞接口,默认会等待远程命令完全执行结束才会返回。你运行的a.out是无限循环程序,永远不会主动退出,所以主线程会一直卡在调用处,永远不会执行到后续的print("Done")和其他逻辑。
实现方案
核心思路是:启动远程程序时将其放到后台运行,同时记录进程PID,后续终止时通过PID给进程发送SIGINT信号(等效于CTRL-C)即可。
关键改动点
- 远程启动命令增加
nohup、后台运行标记&、输出重定向,避免进程随SSH会话断开被杀死,同时让shell立刻返回不阻塞 - 启动命令最后追加
echo $!输出后台进程的PID,本地保存后用于后续终止 - SSH连接实例和远程进程PID需要全局保存,方便终止时复用
完整代码示例
import paramiko from paramiko import AutoAddPolicy # 配置项 RECV_IP_ADDRESS = "你的树莓派IP" SSH_USER = "pi" SSH_PWD = "raspberry" # 全局保存ssh实例和嗅探进程PID ssh_client = None sniffer_pid = None def startPacketReceiver(): global ssh_client, sniffer_pid # 初始化SSH连接 ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(AutoAddPolicy()) ssh_client.connect(RECV_IP_ADDRESS, username=SSH_USER, password=SSH_PWD) # 执行命令:先编译,编译成功后后台启动嗅探程序,输出PID # 输出重定向到/tmp/sniffer.log,也可以改为/dev/null丢弃输出 cmd = ''' sudo gcc Code/test.c && nohup sudo ./a.out > /tmp/sniffer.log 2>&1 & echo $! ''' stdin, stdout, stderr = ssh_client.exec_command(cmd) # 读取PID和错误信息 pid_out = stdout.read().decode().strip() err_out = stderr.read().decode().strip() if err_out: print(f"启动出错:{err_out}") ssh_client.close() ssh_client = None return False sniffer_pid = int(pid_out) print(f"嗅探程序启动成功,PID:{sniffer_pid}") return True def stopPacketReceiver(): global ssh_client, sniffer_pid if not ssh_client or not sniffer_pid: print("没有运行中的嗅探程序") return False # 发送SIGINT信号,等效于CTRL-C cmd = f"sudo kill -SIGINT {sniffer_pid}" stdin, stdout, stderr = ssh_client.exec_command(cmd) # 等待命令执行完成,读取错误信息 err_out = stderr.read().decode().strip() if err_out: print(f"终止出错:{err_out}") # 兜底:直接杀同名进程 ssh_client.exec_command("sudo pkill -f a.out") # 清理资源 ssh_client.close() ssh_client = None sniffer_pid = None print("嗅探程序已终止") return True # 调用示例 if __name__ == "__main__": startPacketReceiver() # 这里可以放你要运行的其他逻辑 import time time.sleep(10) # 模拟运行10秒 stopPacketReceiver()
注意事项
- 如果你的pi用户执行sudo需要输入密码,需要将命令中的
sudo改为echo "raspberry" | sudo -S,通过标准输入传入密码 - 若担心PID记录不准导致杀错进程,可以直接在终止时执行
sudo pkill -f "a.out"批量杀死同名嗅探进程 - 如果你需要获取嗅探程序的输出,可以将重定向路径改为你需要的日志路径,后续通过SSH读取
/tmp/sniffer.log即可
内容的提问来源于stack exchange,提问作者Lyra Orwell
相关产品推荐
相关产品推荐

