借助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        │───────┘
└───────────────────────────┘
