You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:15:03