借助MQTT实现远程控制Linux设备的SSH服务端和客户端 作者:niujiuru 日期:2026-01-20 1, 整体使用JSONRPC2.0 OVER MQTT的技术方案来架构 2,服务端使用: - 在具体的项目代码中调用该模块的: “ModuleInit()” 函数启动初始化、安装和运行 - 在具体的项目代码中调用该模块的: “ModuleExit()” 函数完成退出、停止服务运行 3,服务端原理: - 服务端启动时,会连接到MQTT Broker,订阅主题:/yfkj/device/rpc/imei/cmd,接收来自客户端的指令 - 服务端启动时,会连接到MQTT Broker,发布主题:/yfkj/device/rpc/imei/ack,向客户端发送指令结果 4,客户端使用: - 会编译生成可执行程序“yfkj_ssh_client”,目前支持Linux64和Windows64上位机 - 通过配置文件配置MQTT Broker的地址、用户名、密码以及一些耗时命令的超时时间 5,客户端原理: - 客户端启动时,会连接到MQTT Broker,发布主题:/yfkj/device/rpc/imei/cmd,向服务端发送指令请求 - 客户端启动时,会连接到MQTT Broker,订阅主题:/yfkj/device/rpc/imei/ack,接收服务端的指令结果 6,总体架构图: ┌────────────────────────────┐ │ Shell Client │ │ │ │ stdin ──> JSON-RPC call │ │ Ctrl+C ─> JSON-RPC notify │ │ │ │ prompt 显示 cwd │ └──────────────┬─────────────┘ │ JSON-RPC 2.0 over MQTT │ ┌──────────────▼─────────────┐ │ Shell Server │ │ │ │ Executor (session级) │ │ ├─ cwd │ │ ├─ Exec(cmd) │ │ ├─ Interrupt() │ │ │ │ process group (pgid) │ │ └─ kill(-pgid, SIGINT) │ └────────────────────────────┘ 6,执行流程图: ┌──────────────────────────────────────────┐ │ Remote Client │ │ (Web / App / CLI 运维平台) │ └───────────────┬──────────────────────────┘ │ JSON-RPC 2.0 | - executor.ping │ - executor.exec │ - executor.interrupt │ - executor.close v ┌──────────────────────────────────────────┐ │ MQTT Broker │ │ (QoS1 / KeepAlive / Reconnect) │ └───────────────┬──────────────────────────┘ │ MQTT Message │ Topic: /yfkj/device/rpc/{imei}/cmd v ┌──────────────────────────────────────────┐ │ sshd / MQTTCoupler │ │ │ │ Transport & RPC Adapter Layer │ │ --------------------------------------- │ │ - MQTT 连接管理 │ │ - JSON-RPC 解析 / 校验 │ │ - 方法分发 (Method Dispatch) │ │ │ └───────────────┬──────────────────────────┘ │ 串行 / 单 Session v ┌──────────────────────────────────────────┐ │ shell.Executor │ │ │ │ Session State Layer (≈ SSH Session) │ │ --------------------------------------- │ │ State: │ │ - cwd : 当前工作目录 │ │ - pg : 当前前台进程组 │ │ │ │ Built-in Commands │ │ --------------------------------------- │ │ - cd │ │ - pwd │ │ │ │ Control Interface │ │ --------------------------------------- │ │ Exec() : 启动命令 │ │ Interrupt() : Ctrl+C (SIGINT) │ │ │ └───────────────┬──────────────────────────┘ │ 单次命令执行 v ┌──────────────────────────────────────────┐ │ executeInternal │ │ │ │ Process Lifecycle Layer │ │ --------------------------------------- │ │ - fork/exec │ │ - 新进程组 (setpgid) │ │ - stdout / stderr 限流 │ │ - 超时控制 (context timeout) │ │ - SIGTERM → SIGKILL │ │ │ └───────────────┬──────────────────────────┘ │ MQTT Message | Topic: /yfkj/device/rpc/{imei}/ack v ┌──────────────────────────────────────────┐ │ Linux Kernel │ │ │ │ - Process Group │ │ - Signal Delivery │ │ - Exit Status │ └──────────────────────────────────────────┘ 8, 取消流程图:Ctrl+C Remote Client │ │ shell.execute v ┌───────────────┐ │ sshd │ └──────┬────────┘ │ v ┌───────────────────────────┐ │ shell.Executor │ │ │ │ Exec(): │ │ - 设置 p.Dir = cwd │ │ - 注册前台进程组 pg │ │ │ └──────┬────────────────────┘ │ v ┌───────────────────────────┐ │ executeInternal │ │ │ │ - Start cmd │ │ - setpgid │ │ - onStart(pg) │◄──────┐ │ │ │ │ - wait / timeout │ │ └──────┬────────────────────┘ │ │ │ v │ Command Running │ │ Remote Client Ctrl+C │ │ │ │ shell.interrupt │ v │ ┌───────────────┐ │ │ sshd │ │ └──────┬────────┘ │ │ │ v │ ┌───────────────────────────┐ │ │ Executor.Interrupt() │ │ │ → SIGINT to -pgid │───────┘ └───────────────────────────┘