Go语言Modbusゲートウェイ実践:ffutop modbus-gateway TCP to RTU多スレーブ路由与Docker部署完全チュートリアル

freeFree Technical Resource

This content is free to read, suitable for basic learning and search traffic.

modbus-gateway是由ffutop开源的高いパフォーマンスをModbusゲートウェイ,使用Go语言编写,サポートTCP、RTU、RTU-over-TCP三种协议的任意桥接,基于Slave ID的多スレーブ路由,内置本地虚拟スレーブ,以及多マスター并发队列。本記事从架构原理、インストール编译、設定详解到実践部署,完全介绍如何用modbus-gateway搭建工业级Modbusプロトコル转换ゲートウェイ。

一、modbus-gateway概述

1.1 什么是modbus-gateway

modbus-gateway是一个構成ドライバ的高いパフォーマンスをModbusProtocol Gateway,核心功能是在不同Modbus传输协议之间进行桥接转换。典型场景是:トップマシン(SCADA/PLC)経由Modbus TCP连接ゲートウェイ,ゲートウェイ再経由RS485シリアルポート(Modbus RTU)サイトをつなぐデバイス,実装TCPtoRTU的プロトコル変換。它还サポート基于スレーブID(Slave ID)的路由,可以将不同駅からの住所的リクエスト分发到不同的下游デバイス。

1.2 核心特性

  • 全协议桥接:TCP、RTU、RTU-over-TCP三种协议在上游和下游可任意组合
  • Slave ID路由:按駅からの住所将リクエスト分发到不同下游,サポート範囲(1-10)和リスト(1,2,3)
  • 本地虚拟スレーブ:内置虚拟Modbusslave,サポートmemory/file/mmap三种持久化
  • 多マスター并发:多个上游マスター同时连接,每个下游有独立序列化队列防止バス冲突
  • RS485 RTS控制:完全的RTS信号时序控制,サポート工业级RS485変換器です。
  • 多ゲートウェイ实例:单个进程可运行多个独立ゲートウェイ实例
  • pprof性能分析:内置Go pprof端点,可实时诊断CPU/内存/协程
  • 高いパフォーマンスを:Go原生并发,单实例可処理数千リクエスト/秒
  • 零依赖部署:编译为单个二进制文件,无需运行时环境

1.3 典型アプリケーションシナリオ。

  • TCP to RTU:イーサネット(イーサネット)トップマシンアクセスRS485シリアルデバイス(最も一般的な)
  • RTU to TCP:シリアルポートマスターアクセスイーサネット(イーサネット)Modbus TCPdevice
  • 多スレーブ集約:多条RS485バス的デバイス集約到一个TCPポート
  • 协议中继:RTU-over-TCP与標準TCP/RTU之间转换
  • デバイス模拟:用本地虚拟ステーションからのシミュレーション不存在的Modbusdevice
  • 远程アクセス:将现场RS485デバイス暴露为TCP服务,サポート远程デバッグ

二、架构原理

modbus-gateway的架构分为三层:上游(Upstream)、ゲートウェイ核心(Gateway)、下游(Downstream)。

┌─────────────────────────────────────────────────────────────┐
│                      Upstreams(上游)                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │ TCP Master   │  │ RTU-over-TCP │  │ RTU Master   │      │
│  │ 0.0.0.0:502  │  │ 0.0.0.0:503  │  │ /dev/ttyS0   │      │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘      │
└─────────┼─────────────────┼─────────────────┼──────────────┘
          │                 │                 │
┌─────────▼─────────────────▼─────────────────▼──────────────┐
│                   Gateway Core(ゲートウェイ核心)                    │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  Queue   │→│ Buffer   │→│Serializer│→│SlaveID   │   │
│  │  队列缓冲 │  │  バッファ  │  │ 序列化   │  │Router    │   │
│  └──────────┘  └──────────┘  └──────────┘  └────┬─────┘   │
│                                          ┌───────▼───────┐  │
│                                          │ Local Slave   │  │
│                                          │ 本地虚拟スレーブ   │  │
│                                          └───────────────┘  │
└──────────────────────────────┬──────────────────────────────┘
                               │
┌──────────────────────────────▼──────────────────────────────┐
│                     Downstreams(下游)                       │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │ RTU Slave    │  │ TCP Slave    │  │ Local Slave  │      │
│  │ slave_ids:   │  │ slave_ids:   │  │ slave_ids:   │      │
│  │ 1-10         │  │ 11-20        │  │ 100          │      │
│  │ /dev/ttyUSB0 │  │ 192.168.1.50 │  │ mmap存储     │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘

2.1 关键机制説明

  • 队列缓冲(Queue Buffer):每个上游连接的リクエスト先进入队列,避免リクエスト丢失
  • 序列化(Serializer):同一下游的リクエスト被串行化执行,防止RS485バス冲突
  • Slave ID路由:根据リクエスト中駅からの住所,查表决定发往哪个下游
  • 本地虚拟スレーブ:路由到localタイプ的リクエスト由ゲートウェイ内部直接レスポンス,无需真实デバイス

三、インストール与编译

# 方式一:源码编译(おすすめ)
git clone https://github.com/ffutop/modbus-gateway.git
cd modbus-gateway
go build -o modbus-gateway

# 交叉编译(在Linux上编译Windows版本)
GOOS=windows GOARCH=amd64 go build -o modbus-gateway.exe

# 交叉编译ARM版本(Raspberry Pi/組込みデバイス)
GOOS=linux GOARCH=arm GOARM=7 go build -o modbus-gateway-arm

# 方式二:下载预编译二进制
# 从GitHub Releasesページ下载对应プラットフォーム的二进制
# https://github.com/ffutop/modbus-gateway/releases

# 验证インストール
./modbus-gateway -help
# 出力命令行参数説明

# 表示版本
./modbus-gateway -version

四、基础設定:TCP to RTUゲートウェイ

最も一般的な的场景:トップマシン経由Modbus TCP连接ゲートウェイ,ゲートウェイ通過RS485シリアルポートサイトをつなぐRTUdevice。

# config-tcp2rtu.yaml - TCP to RTU基础設定
gateways:
  - name: "tcp-to-rtu-gateway"
    # 上游:监听TCPポート,接受トップマシン连接
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"   # 监听すべての网卡的502ポート

    # 下游:経由RS485シリアルポートサイトをつなぐデバイス
    downstreams:
      - type: "rtu"
        slave_ids: "1-10"          # slaveID 1-10的リクエスト路由到此シリアルポート
        serial:
          device: "/dev/ttyUSB0"    # USB转RS485デバイス
          baud_rate: 9600           # Baud rate
          data_bits: 8              # data bit
          parity: "N"               # check digit N=无 E=偶 O=奇
          stop_bits: 1              # stop bit
          timeout: "500ms"          # 読み取りタイムアウト
          rqst_pause: "100ms"       # リクエスト间最小間隔

log:
  level: "info"                     # 日志级别 debug/info/warn/error
  file: ""                          # 日志文件路径,空=出力到stdout
# 启动ゲートウェイ
./modbus-gateway -config config-tcp2rtu.yaml

# 测试:用pymodbus或QModMaster连接ゲートウェイ
# 连接アドレス:ゲートウェイIP:502
# slaveID:1-10(会被路由到RS485シリアルポート)
# function code:01/02/03/04/05/06/15/16すべてサポート

# 表示日志確認リクエスト转发
# INFO tcp master accepted conn from 192.168.1.100:54321
# INFO routing slave_id=1 to downstream rtu:/dev/ttyUSB0
# INFO request FC=03 addr=0 count=10 -> response ok

五、多スレーブ路由設定

当现场有多条RS485バス或多种タイプデバイス时,可以経由Slave ID路由将リクエスト分发到不同下游。

# config-multi-slave.yaml - 多スレーブ路由
gateways:
  - name: "multi-slave-gateway"
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"

    downstreams:
      # 下游1:RS485バスA - Temperature & Humidity Sensor(slave1-10)
      - type: "rtu"
        slave_ids: "1-10"
        serial:
          device: "/dev/ttyUSB0"
          baud_rate: 9600
          data_bits: 8
          parity: "N"
          stop_bits: 1
          timeout: "500ms"

      # 下游2:RS485バスB - パワーメーター(slave11-20)
      - type: "rtu"
        slave_ids: "11-20"
        serial:
          device: "/dev/ttyUSB1"
          baud_rate: 19200
          data_bits: 8
          parity: "E"           # パワーメーター常用ダブルチェック
          stop_bits: 1
          timeout: "300ms"

      # 下游3:Modbus TCPdevice - 周波数変換器(slave21)
      - type: "tcp"
        slave_ids: "21"
        tcp:
          address: "192.168.1.50:502"

      # 下游4:本地虚拟スレーブ - ゲートウェイステータス(slave100)
      - type: "local"
        slave_ids: "100"
        local:
          persistence:
            type: "memory"      # 内存存储,再起動后丢失

log:
  level: "info"

路由ルール説明:

  • slave_ids: "1-10":マッチングスレーブID 1到10的すべてのリクエスト
  • slave_ids: "1,2,3":マッチングスレーブID 1、2、3
  • slave_ids: "1-5,10,20-25":混合範囲和リスト
  • slave_ids: ""(空):マッチングすべての未被其他下游マッチング的リクエスト(デフォルト路由)
  • もし一个スレーブID被多个下游マッチング,按設定顺序第一个マッチング的下游生效

六、本地虚拟スレーブ

modbus-gateway内置了本地虚拟スレーブ功能,可以在没実際のデバイス的情况下レスポンスModbusRequest,サポート三种持久化方式。

# config-local-slave.yaml - 本地虚拟ステーションからの設定
gateways:
  - name: "local-slave-demo"
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"

    downstreams:
      # 虚拟スレーブ1:内存モード(再起動データ丢失,适合测试)
      - type: "local"
        slave_ids: "100"
        local:
          persistence:
            type: "memory"

      # 虚拟スレーブ2:文件モード(データ持久化到文件)
      - type: "local"
        slave_ids: "101"
        local:
          persistence:
            type: "file"
            path: "/data/modbus-slave-101/"

      # 虚拟スレーブ3:mmapモード(内存マッピング文件,高いパフォーマンスを+持久化)
      - type: "local"
        slave_ids: "102"
        local:
          persistence:
            type: "mmap"
            path: "/data/modbus-slave-102/"

log:
  level: "debug"

6.1 三种持久化方式对比

方式速度持久化適用可能なシーン
memory最快否(再起動丢失)测试、临时模拟
file较慢需要持久化但写入不频繁
mmap生产环境,高频読み書き

七、RTU-over-TCP設定

RTU-over-TCP是将Modbus RTUフレーム直接封装在TCP中传输(不加MBAP Head),常用于某些シリアルサーバーデバイス。modbus-gatewayサポートRTU-over-TCP作为上游或下游。

# config-rtu-over-tcp.yaml - RTU-over-TCP設定
gateways:
  - name: "rtu-over-tcp-gateway"
    upstreams:
      # 上游1:標準Modbus TCP(带MBAP Head)
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"

      # 上游2:RTU-over-TCP(裸RTUフレーム)
      - type: "rtu-over-tcp"
        tcp:
          address: "0.0.0.0:503"   # 用不同ポート区分

    downstreams:
      # 下游:標準RTUSerial Port Device
      - type: "rtu"
        slave_ids: "1-10"
        serial:
          device: "/dev/ttyUSB0"
          baud_rate: 9600
          data_bits: 8
          parity: "N"
          stop_bits: 1

      # 下游:RTU-over-TCPdevice(如某些シリアルサーバー)
      - type: "rtu-over-tcp"
        slave_ids: "11-20"
        tcp:
          address: "192.168.1.100:4001"  # シリアルサーバーアドレス

log:
  level: "info"

八、多ゲートウェイ实例

单个modbus-gateway进程可以运行多个独立的ゲートウェイ实例,每个实例有自己的上游监听和下游连接,互不干渉。

# config-multi-gateway.yaml - 多ゲートウェイ实例
gateways:
  # 实例1:车间Aゲートウェイ
  - name: "workshop-a"
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"
    downstreams:
      - type: "rtu"
        slave_ids: "1-20"
        serial:
          device: "/dev/ttyUSB0"
          baud_rate: 9600
          data_bits: 8
          parity: "N"
          stop_bits: 1

  # 实例2:车间Bゲートウェイ
  - name: "workshop-b"
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:503"     # 不同ポート
    downstreams:
      - type: "rtu"
        slave_ids: "1-20"
        serial:
          device: "/dev/ttyUSB1"
          baud_rate: 19200
          data_bits: 8
          parity: "E"
          stop_bits: 1

  # 实例3:能源モニタリングゲートウェイ
  - name: "energy-monitor"
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:504"
    downstreams:
      - type: "tcp"
        slave_ids: "1-5"
        tcp:
          address: "192.168.1.50:502"

# 性能分析(可选)
pprof:
  enabled: true
  address: "localhost:6060"

log:
  level: "info"
  file: "/var/log/modbus-gateway.log"

九、RS485エキスパート控制

对于需要精确控制RS485收发切换的工业场景,modbus-gateway提供了完全的RTS信号时序控制。

# config-rs485.yaml - RS485エキスパート控制
gateways:
  - name: "rs485-industrial"
    upstreams:
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"
    downstreams:
      - type: "rtu"
        slave_ids: "1-10"
        serial:
          device: "/dev/ttyUSB0"
          baud_rate: 115200
          data_bits: 8
          parity: "N"
          stop_bits: 1
          timeout: "300ms"
          rqst_pause: "50ms"

          # RS485 RTS控制
          rs485: true                          # EnableRTS控制
          delay_rts_before_send: "1ms"         # 送信前RTS置位延迟
          delay_rts_after_send: "1ms"          # 送信后RTS复位延迟
          rts_high_during_send: true           # 送信期间RTS保持高电平
          rts_high_after_send: false           # 送信后RTS低电平

log:
  level: "debug"

9.1 RTS时序説明

  • rs485: true:有効硬件RTSフロー制御,自动切换收发方向
  • delay_rts_before_send:RTS置位后待機中多久再送信データ,确保RS485芯片切换到送信モード
  • delay_rts_after_send:データ送信完成后待機中多久再复位RTS,确保最后一バイト単位。送信完毕
  • rts_high_during_send:送信期间RTS电平(true=高电平,false=低电平),取决于RS485芯片的极性
  • commonRS485芯片如MAX485:DE/RE引脚通常高电平送信、低电平受信

十、Docker部署

# Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
RUN apk add --no-cache git
RUN git clone https://github.com/ffutop/modbus-gateway.git .
RUN go build -o modbus-gateway

FROM alpine:3.19
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/modbus-gateway /usr/local/bin/
ENTRYPOINT ["modbus-gateway"]
CMD ["-config", "/etc/modbus-gateway/config.yaml"]
# docker-compose.yaml
version: "3.8"
services:
  modbus-gateway:
    build: .
    container_name: modbus-gateway
    restart: unless-stopped
    ports:
      - "502:502"     # Modbus TCP
      - "503:503"     # RTU-over-TCP
      - "6060:6060"   # pprof
    devices:
      - "/dev/ttyUSB0:/dev/ttyUSB0"   # RS485シリアルポート
      - "/dev/ttyUSB1:/dev/ttyUSB1"
    volumes:
      - ./config.yaml:/etc/modbus-gateway/config.yaml:ro
      - ./data:/data
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
# 构建并启动
docker-compose up -d

# 表示日志
docker-compose logs -f

# 再起動
docker-compose restart

十一、完全実践:プラントエネルギー監視ゲートウェイ

以下是一个完全的生产环境設定案例:工厂能源モニタリング系统,経由modbus-gateway将车间的パワーメーター、温湿度センサー和PLC统一接入SCADAsystem。

# factory-energy.yaml - プラントエネルギー監視ゲートウェイ
gateways:
  - name: "factory-energy-gateway"
    upstreams:
      # SCADA系统経由TCPconnect
      - type: "tcp"
        tcp:
          address: "0.0.0.0:502"

    downstreams:
      # 1号RS485バス:パワーメーター(slave1-8)
      - type: "rtu"
        slave_ids: "1-8"
        serial:
          device: "/dev/ttyUSB0"
          baud_rate: 9600
          data_bits: 8
          parity: "E"
          stop_bits: 1
          timeout: "500ms"
          rqst_pause: "100ms"
          rs485: true
          delay_rts_before_send: "1ms"
          delay_rts_after_send: "2ms"

      # 2号RS485バス:Temperature & Humidity Sensor(slave9-16)
      - type: "rtu"
        slave_ids: "9-16"
        serial:
          device: "/dev/ttyUSB1"
          baud_rate: 4800
          data_bits: 8
          parity: "N"
          stop_bits: 1
          timeout: "1000ms"

      # 3号RS485バス:PLC(slave17-20)
      - type: "rtu"
        slave_ids: "17-20"
        serial:
          device: "/dev/ttyUSB2"
          baud_rate: 19200
          data_bits: 8
          parity: "N"
          stop_bits: 1
          timeout: "300ms"

      # イーサネット(イーサネット)デバイス:スマートメーター(slave21)
      - type: "tcp"
        slave_ids: "21"
        tcp:
          address: "192.168.1.50:502"

      # 本地虚拟スレーブ:ゲートウェイ自身ステータス(slave100)
      - type: "local"
        slave_ids: "100"
        local:
          persistence:
            type: "mmap"
            path: "/data/gateway-status/"

# 性能モニタリング
pprof:
  enabled: true
  address: "localhost:6060"

log:
  level: "info"
  file: "/var/log/modbus-gateway/factory-energy.log"

11.1 系统架构説明

  • SCADA系统连接ゲートウェイTCP 502ポート,统一アクセス全装備。
  • slave1-8的リクエスト路由到USB0(パワーメーター,9600ダブルチェック)
  • slave9-16的リクエスト路由到USB1(Temperature & Humidity Sensor,4800検証なし。)
  • slave17-20的リクエスト路由到USB2(PLC,19200検証なし。)
  • slave21的リクエスト转发到イーサネット(イーサネット)スマートメーター
  • slave100由ゲートウェイ本地虚拟スレーブレスポンス,可写入ゲートウェイ実行状態の状態
  • 每个下游有独立序列化队列,不会因为一条バス慢而影响其他バス

十二、パフォーマンス最適化与モニタリング

12.1 pprof性能分析

# Enablepprof后,アクセス以下端点:
# http://localhost:6060/debug/pprof/          - 概览
# http://localhost:6060/debug/pprof/heap       - 内存分析
# http://localhost:6060/debug/pprof/profile    - CPU分析(30秒)
# http://localhost:6060/debug/pprof/goroutine  - 协程分析

# 用go tool分析CPU
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# 进入pprof交互界面后:
# top10          - ViewCPU占用前10的函数
# web            - 生成调用图(需要graphviz)
# list function  - 表示函数级别的耗时

# 分析内存
go tool pprof http://localhost:6060/debug/pprof/heap
# inuse_space    - 当前内存占用
# alloc_space    - 累计分配

12.2 パフォーマンス最適化建议

  • 合理設定timeout:タイムアウト時間应略大于デバイス最大応答時間,过短导致丢包,过长降低效率
  • rqst_pause调优:リクエスト間隔根据デバイスレスポンス速度调整,慢速デバイス建议100-200ms
  • ボーレート最大化:在通信稳定的前提下尽量使用高ボーレート(115200)
  • 分批読み取り:トップマシン应尽量バッチ読み取り连续アドレス,减少リクエスト次数
  • 连接复用:トップマシン保持长连接,避免频繁建立TCPconnect
  • slaveID规划:同一バス上的デバイス使用连续的スレーブID,便于路由設定

十三、よくある質問与トラブルシューティング

問題原因解決方法
上游接続成功です。但応答なし。slaveID未マッチング到任何下游チェックslave_ids設定,确保リクエスト的スレーブID在路由範囲内
RTUデバイスが応答しませんシリアルパラメータの不一致核对ボーレート、data bit、check digit、ストップ·ビット与デバイス一致
RS485通信不稳定RTS时序不正确调整delay_rts_before/after_send,チェック配線和終端抵抗
多マスター时データ错乱序列化队列未生效確認每个下游只有一个序列化队列,チェック日志
TCP连接被拒绝ポート被占用或ファイアウォールチェック502ポート是否被其他程序占用,开放ファイアウォール
虚拟スレーブデータ丢失使用了memoryモード改用file或mmapモード持久化
高延迟timeout設定过大根据デバイス实际応答時間调小timeout
シリアルポート权限不足用户无シリアルポートアクセス権将用户加入dialout组:sudo usermod -aG dialout $USER
RTU-over-TCP不工作对端是標準TCP而非RTU-over-TCP機器の確認协议タイプ,標準TCP用type: tcp
内存持续增长连接泄漏或データ累积用pprof分析,チェック上游连接是否正常关闭

十四、設定参照クイックチェック·テーブル

設定项Typeデフォルト値説明
gateways[].namestring-ゲートウェイ名称,用于日志标识
upstreams[].typeenum-tcp / rtu / rtu-over-tcp
upstreams[].tcp.addressstring-TCPListen address
downstreams[].typeenum-tcp / rtu / rtu-over-tcp / local
downstreams[].slave_idsstring""路由ルール,空=マッチングすべての
serial.devicestring-シリアルデバイス路径
serial.baud_rateint-Baud rate
serial.data_bitsint8data bit
serial.paritystring"N"N/E/O
serial.stop_bitsint1stop bit
serial.timeoutduration"500ms"読み取りタイムアウト
serial.rqst_pauseduration"100ms"リクエスト间最小間隔
serial.rs485boolfalseEnableRTS控制
local.persistence.typeenum-memory / file / mmap
local.persistence.pathstring-持久化目录
pprof.enabledboolfalse有効性能分析
log.levelstring"info"debug/info/warn/error
log.filestring""日志文件路径

十五、学习リソース

  • プロジェクトの住所:https://github.com/ffutop/modbus-gateway
  • 官方ドキュメント:http://modbus-gateway.ffutop.com/
  • Modbusプロトコル规范:https://modbus.org/specs.php
  • Go语言官网:https://go.dev/

modbus-gateway作为Go语言编写的高いパフォーマンスをModbusゲートウェイ,以構成ドライバ的方式実装了TCP/RTU/RTU-over-TCP的任意协议桥接,基于Slave ID的多スレーブ路由和本地虚拟スレーブ功能使其能够应对复杂的工业现场需求。本記事提供的从基础TCP to RTU到多ゲートウェイ实例、RS485エキスパート控制、Docker部署和完全工厂能源モニタリングの実践設定,可直接使用する。于生产环境部署。建议在部署前先用本地虚拟スレーブ测试路由ルール,再逐步接入真实デバイス。

📦

VIP专属:Go语言Modbusゲートウェイ完全なコードパッケージ

ffutop/modbus-gateway YAML構成ドライバ,TCP/RTU/ローカルマルチプロトコル変換,工場エネルギー監視を含む。

Activate VIP即可下载完全代码,同时解锁 30+ 工程実践パッケージの内容:スクリプトのデバッグ、クイックチェック·テーブル、项目模板、トラブルシューティング案例……

前往VIP资料库下载 → 月费仅9.9元 / 年费199元
Put this resource to use in a real project?

Go to the Tool Center for message parsing, CRC verification and device debugging, or submit your requirements for selection and integration advice.

Engineer Membership

Turn this article into actionable debugging resources

After activation, you can use advanced message parsing, resource pack downloads, code examples, engineering cases and priority technical support, suitable for real project delivery.

Unlimited Advanced Tools
Resource & Code Packs
Complete Engineering Case Library
Priority Technical Support