编辑 | blame | 历史 | 原始文档

JMS 透析机 TCP 联机服务 — 实施部署文档

1. 系统概述

JMS 联机服务用于管理与监控多台 GC-110N 透析设备。通过持久 TCP 长连接 + 定时 K 指令轮询,实时采集 32 项治疗参数,经 MQTT / 阿里云 IoT 上传至云端,并提供本地 Web 监控大屏。

┌──────────┐   TCP:10001    ┌─────────────────┐    MQTT     ┌──────────────┐
│ GC-110N  │←──────────────→│  jms-connection  │───────────→│  MQTT Broker  │
│ 透析机 1  │   K 轮询 (10s)  │     -service     │            └──────────────┘
└──────────┘                │                  │
     ···                    │  dashboard:3100  │   HTTP     ┌──────────────┐
┌──────────┐                │  ← 浏览器访问      │───────────→│ 阿里云 IoT     │
│ GC-110N  │←──────────────→│                  │  postProps │  (三元组API)   │
│ 透析机 N  │                └─────────────────┘            └──────────────┘

2. 环境要求

项目 要求
操作系统 Linux(推荐 Ubuntu 20.04+ / CentOS 7+)或 Windows Server 2016+
Node.js ≥ 18.x(推荐 20 LTS)
npm ≥ 9.x(随 Node.js 附带)
内存 ≥ 256 MB(本服务占用 ~80 MB)
磁盘 ≥ 1 GB(日志滚动保留 30 天)
网络 需与 GC-110N 设备在同一局域网,或能通过路由访问设备 TCP 端口

2.1 检查 Node.js 版本

node -v   # 应输出 v18.x 或 v20.x
npm -v    # 应输出 9.x 或 10.x

2.2 安装 Node.js(如未安装)

Ubuntu/Debian:
bash curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt-get install -y nodejs

CentOS/RHEL:
bash curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - sudo yum install -y nodejs

Windows:
https://nodejs.org 下载 LTS 安装包,勾选「Add to PATH」。

3. 部署步骤

3.1 获取代码

# 将部署包解压或从 Git 拉取
cd /opt
tar -xzf jms-connection-service.tar.gz -C /opt/
# 或: git clone <repo-url> /opt/jms-connection-service

cd /opt/jms-connection-service

3.2 安装依赖

npm install --production

仅安装生产依赖(dependencies),不安装 devDependencies。

3.3 配置

复制并修改配置文件:

# 如无可直接编辑 config.json(已内置在部署包中)
vi config.json

详细配置项说明见 第 4 节

3.4 验证连通性

在启动服务前,确认服务器能连通 GC-110N 设备:

# 测试 TCP 端口(替换为实际 IP 和端口)
nc -zv 192.168.160.1 10001
# 或 Windows:
# Test-NetConnection -ComputerName 192.168.160.1 -Port 10001

3.5 启动服务

# 前台运行(调试用)
node index.js

# 后台运行(生产推荐,使用 PM2)
npm install -g pm2
pm2 start index.js --name jms-connection-service
pm2 save
pm2 startup   # 设置开机自启

启动成功后控制台输出:

配置校验通过: 1/1 台设备启用
联机服务启动
日志目录: /opt/jms-connection-service/logs  保留: 30 天
轮询间隔: 10s  重连退避: 3s~60s
Dashboard 已启动: http://0.0.0.0:3100

联机服务已启动 → Dashboard: http://localhost:3100

3.6 访问监控面板

浏览器打开 http://<服务器IP>:3100,可看到设备连接状态、实时数据和上传状态。

4. 配置说明

配置文件为根目录下的 config.json,格式如下:

{
  // ── 全局参数 ──
  "pollIntervalMs": 10000,       // K 轮询间隔(毫秒),默认 10000 = 10s
  "connectTimeoutMs": 5000,      // TCP 握手超时(毫秒)
  "reconnectBaseMs": 3000,       // 重连退避基数(毫秒)
  "reconnectMaxMs": 60000,       // 重连退避上限(毫秒),实际延迟 = min(base*2^(n-1), max)
  "logDir": "./logs",            // 日志目录(相对路径基于项目根目录)
  "logRetentionDays": 30,        // 日志保留天数
  "dashboardPort": 3100,         // 监控大屏 HTTP 端口

  // ── MQTT 上传(可选) ──
  "mqtt": {
    "enabled": false,            // 是否启用 MQTT 上传
    "brokerUrl": "mqtt.ihemodialysis.com",  // MQTT Broker 地址(不含协议前缀)
    "port": 62283,               // MQTT 端口
    "username": "data",          // 认证用户名
    "password": "data#2018",     // 认证密码
    "reconnectPeriod": 5000,     // MQTT 重连间隔(毫秒)
    "clientCode": "CLIENT9227100800901fcKB",  // 客户端标识
    "defaultTopicPrefix": "touxiji",          // 默认 Topic 前缀,发布 topic = {prefix}/{deviceNo}
    "qos": 1                     // MQTT QoS 级别
  },

  // ── 阿里云 IoT 上传(可选) ──
  "aliyun": {
    "enabled": true,             // 是否启用阿里云上传
    "autoRegister": true,        // 是否自动注册设备(三元组不存在时自动创建)
    "tupleApiBaseUrl": "https://things.icoldchain.cn/",  // 三元组 API 地址
    "tupleApiPath": "device/info/getAliyunDeviceSecret", // 三元组 API 路径
    "tupleRetryCooldownMs": 60000  // 三元组请求失败后冷却时间(毫秒)
  },

  // ── 设备列表 ──
  "devices": [
    {
      "ip": "192.168.160.1",     // 设备 IP 地址(必填)
      "port": 10001,             // 设备 TCP 端口(必填,GC-110N 默认 10001)
      "serialNumber": "xy123",   // 设备序列号(必填,用于上传标识)
      "enabled": true            // 是否启用(false 则跳过此设备)
    }
    // 可添加多台设备...
  ]
}

4.1 重连退避说明

服务使用指数退避策略处理断线重连:

断开次数 延迟时间(base=3000, max=60000)
第 1 次 3s
第 2 次 6s
第 3 次 12s
第 4 次 24s
第 5 次 48s
第 6 次+ 60s(达到上限)

连接成功后计数器重置。

4.2 设备配置示例

"devices": [
  { "ip": "192.168.1.101", "port": 10001, "serialNumber": "D001", "enabled": true },
  { "ip": "192.168.1.102", "port": 10001, "serialNumber": "D002", "enabled": true },
  { "ip": "192.168.1.103", "port": 10001, "serialNumber": "D003", "enabled": false }
]

5. 运行管理

5.1 PM2 常用命令

pm2 status                          # 查看进程状态
pm2 logs jms-connection-service     # 查看实时日志
pm2 restart jms-connection-service  # 重启服务
pm2 stop jms-connection-service     # 停止服务
pm2 delete jms-connection-service   # 从 PM2 移除

5.2 日志查看

日志文件位于 logDir 配置的目录中(默认 ./logs),按天滚动:

logs/
├── service.2026-05-10.log
├── service.2026-05-11.log
└── service.2026-05-12.log    # 最多保留 30 天

日志中的关键符号:

符号 含义
发送 K 请求
收到 K 响应(含原始报文)
TCP 连接成功 / 上传通道连接成功
TCP 断开
计划重连
上传成功
错误
! 警告

5.3 优雅停止

# PM2 方式
pm2 stop jms-connection-service

# 直接进程方式(发送 SIGINT)
kill -2 $(pgrep -f "node index.js")

服务会依次关闭:设备连接 → 上传模块 → Dashboard → 日志清理定时器。

6. 网络与防火墙

6.1 出站连接

服务作为 TCP 客户端,需要访问以下目标:

目标 协议 端口 用途
GC-110N 设备 IP TCP 10001(可配置) K 指令轮询
MQTT Broker TCP 62283(可配置) MQTT 上传
阿里云 IoT SDK TCP 443 (TLS) 阿里云属性上报
三元组 API HTTPS 443 获取设备三元组

6.2 入站连接

来源 协议 端口 用途
浏览器(局域网) HTTP 3100(可配置) 监控大屏
浏览器(局域网) WebSocket 3100(同 HTTP) 实时数据推送

6.3 防火墙配置示例(Linux iptables)

# 允许 Dashboard 入站(仅内网)
iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 3100 -j ACCEPT
iptables -A INPUT -p tcp --dport 3100 -j DROP

# 出站一般默认为 ACCEPT,无需额外配置

6.4 Windows 防火墙

# 允许 Dashboard 端口入站
New-NetFirewallRule -DisplayName "JMS Dashboard" -Direction Inbound -Protocol TCP -LocalPort 3100 -Action Allow

7. 监控面板使用

7.1 面板概览

访问 http://<服务器IP>:3100 进入监控大屏:

  • 顶部状态栏:协议版本、WebSocket 连接状态、轮询间隔
  • 汇总卡片:设备总数、在线数、数据正常数、异常数、MQTT/阿里云上传状态、最近上传结果
  • 设备列表:每台设备的 IP、序列号、连接状态、最后数据时间、最后上传时间、字段数、重连次数、错误信息

7.2 查看设备详情

点击设备行可展开详情面板,显示:

  • 32 项治疗参数的实时值(字段 ID、中文名称、数值、单位)
  • 原始 K 格式报文(如 K0000A00010B00005...

再次点击收起。

7.3 状态指示灯

颜色 含义
🟢 绿色 在线 / 正常
🟡 黄色 连接中
🔵 蓝色 等待轮询
🔴 红色 断线 / 异常
⚫ 灰色 已禁用 / 等待

8. 常见问题排查

8.1 设备显示「断线」

  1. 检查网络连通性ping <设备IP>nc -zv <设备IP> <端口>
  2. 检查设备是否开机:GC-110N 设备需处于治疗或待机状态
  3. 检查防火墙:确认服务器到设备的 TCP 端口未被拦截
  4. 查看日志logs/service.YYYY-MM-DD.log 搜索

8.2 收不到数据 / 字段数为 0

  1. 确认设备已进入治疗状态(待机状态下 K 指令返回数据可能有限)
  2. 查看日志中 行,检查原始报文格式是否正确(应以 K 开头 + 4 位状态码)
  3. 确认设备固件支持 K 格式协议

8.3 阿里云上传失败

  1. 三元组获取失败:检查 aliyun.tupleApiBaseUrl 能否从服务器访问(curl <url>
  2. 属性上报超时:检查服务器到阿里云 IoT 的 443 端口连通性
  3. 设备未注册:设置 aliyun.autoRegister: true 自动注册,或先在阿里云 IoT 平台创建设备
  4. 冷却期:三元组请求失败后进入 60s 冷却期,期间不重试,查看日志 tuple 事件

8.4 MQTT 上传不工作

  1. 确认 mqtt.enabled: true
  2. 检查 MQTT Broker 地址和端口是否可达
  3. 确认用户名密码正确
  4. Dashboard 的 MQTT 卡片会显示当前连接状态

8.5 Dashboard 打不开

  1. 确认 dashboardPort 未被占用:netstat -tlnp | grep 3100
  2. 确认防火墙允许对应端口入站
  3. 确认服务已正常启动(查看控制台输出)

8.6 日志文件过大

服务内置了日志清理机制,每小时检查一次并删除超过保留天数的日志。如需手动清理:

# 删除 30 天前的日志
find ./logs -name "*.log" -mtime +30 -delete

9. 目录结构

jms-connection-service/
├── index.js                       # 入口文件
├── config.json                    # 配置文件 ★
├── package.json                   # 依赖声明
├── lib/
│   ├── logger.js                  # 日志模块(按天滚动,控制台彩色 + 文件纯文本)
│   ├── data-cache.js              # 内存数据缓存(Map<ip, deviceData>)
│   ├── device-manager.js          # 设备管理(遍历 config.devices 创建连接)
│   ├── device-connection.js       # 单设备 TCP 长连接 + K 轮询 + 重连
│   ├── protocol.js                # GC-110N K 格式解析器
│   └── upload/
│       ├── index.js               # 上传总控(顺序执行 MQTT → 阿里云)
│       ├── mqtt-uploader.js       # MQTT 单例客户端
│       ├── aliyun-uploader.js     # 阿里云 IoT SDK 设备实例池
│       ├── tuple-api.js           # 三元组 API HTTP 请求
│       └── field-mapper.js        # GC-110N ID → 阿里云 identifier 映射
└── dashboard/
    ├── server.js                  # HTTP + WebSocket 服务
    └── public/
        └── index.html             # 监控大屏单页

10. 附录:GC-110N K 格式字段表

ID 中文名称 单位 宽度(字节)
A 目标除水量 L 5
B 当前除水量 L 5
C 除水速度 L/h 5
D 血液流量 mL/min 5
E 注射器泵速度 mL/h 5
F 透析液温度 5
G 透析液浓度 mS/cm 5
H 静脉压 mmHg 5
I 透析液压 mmHg 5
J TMP mmHg 5
K 治疗经过时间 min 5
L 透析液流量 mL/min 5
a 液温报警 1
b 浓度报警 1
c 静脉压报警 1
d 液压报警 1
e TMP 报警 1
f 气泡检测报警 1
g 漏血报警 1
h 其他报警 1
M 治疗中标志 1
N 治疗模式 1
O 目标补液量 L 5
P 当前补液量 L 5
Q 补液速度 L/h 5
R 补液温度 5
S 血压测量时刻 HHMMSS 6(变长)
T 收缩压 mmHg 5
U 舒张压 mmHg 5
V 脉搏 bpm 5
i 血压报警 1
W 注射器泵累计量 mL 5