modbus-gateway是由ffutop오픈소스的高性能Modbus게이트웨이,使用Go언어编写,支持TCP、RTU、RTU-over-TCP三种프로토콜的任意桥接,基于Slave ID的多슬레이브路由,内置本地虚拟슬레이브,以及多마스터并发队列。本文从架构원리、安装编译、설정详解到实战部署,完整介绍如何用modbus-gateway搭建산업용Modbus프로토콜转换게이트웨이。
一、modbus-gateway개요
1.1 什么是modbus-gateway
modbus-gateway是一个설정驱动的高性能Modbus프로토콜 게이트웨이,核心功能是在不同Modbus传输프로토콜之间进行桥接转换。典型시나리오是:上位机(SCADA/PLC)通过Modbus TCP연결게이트웨이,게이트웨이再通过RS485시리얼 포트(Modbus RTU)연결现场设备,实现TCP到RTU的프로토콜转换。它还支持基于슬레이브ID(Slave ID)的路由,可以将不同슬레이브 주소的请求分发到不同的下游设备。
1.2 核心特性
- 全프로토콜桥接:TCP、RTU、RTU-over-TCP三种프로토콜在上游和下游可任意组合
- Slave ID路由:按슬레이브 주소将请求分发到不同下游,支持范围(1-10)和列表(1,2,3)
- 本地虚拟슬레이브:内置虚拟Modbus슬레이브,支持memory/file/mmap三种持久化
- 多마스터并发:多个上游마스터同时연결,每个下游有独立시퀀스化队列防止总线冲突
- RS485 RTS控制:完整的RTS信号时序控制,支持산업용RS485컨버터
- 多게이트웨이实例:单个进程可运行多个独立게이트웨이实例
- pprof性能分析:内置Go pprof端点,可实时诊断CPU/内存/协程
- 高性能:Go原生并发,单实例可处理数千请求/秒
- 零依赖部署:编译为单个2진수文件,无需运行时환경
1.3 典型적용시나리오
- TCP转RTU:以太网上位机访问RS485시리얼 포트设备(最常见)
- RTU转TCP:시리얼 포트마스터访问以太网Modbus TCP设备
- 多슬레이브聚合:多条RS485总线的设备聚合到一个TCP포트
- 프로토콜中继:RTU-over-TCP与표준TCP/RTU之间转换
- 设备模拟:用本地虚拟슬레이브模拟不存在的Modbus设备
- 远程访问:将现场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버전(树莓派/嵌入式设备)
GOOS=linux GOARCH=arm GOARM=7 go build -o modbus-gateway-arm
# 방식二:下载预编译2진수
# 从GitHub Releases页面下载对应平台的2진수
# https://github.com/ffutop/modbus-gateway/releases
# 验证安装
./modbus-gateway -help
# 출력命令行매개변수설명
# 보기버전
./modbus-gateway -version
四、基础설정:TCP转RTU게이트웨이
最常见的시나리오:上位机通过Modbus TCP연결게이트웨이,게이트웨이通过RS485시리얼 포트연결现场RTU设备。
# config-tcp2rtu.yaml - TCP转RTU基础설정
gateways:
- name: "tcp-to-rtu-gateway"
# 上游:监听TCP포트,接受上位机연결
upstreams:
- type: "tcp"
tcp:
주소: "0.0.0.0:502" # 监听所有网卡的502포트
# 下游:通过RS485시리얼 포트연결现场设备
downstreams:
- type: "rtu"
slave_ids: "1-10" # 슬레이브ID 1-10的请求路由到此시리얼 포트
serial:
device: "/dev/ttyUSB0" # USB转RS485设备
baud_rate: 9600 # 통신 속도
데이터_bits: 8 # 데이터 비트
parity: "N" # 패리티 N=无 E=偶 O=奇
stop_bits: 1 # 정지 비트
timeout: "500ms" # 읽기超时
rqst_pause: "100ms" # 请求间最小间隔
log:
level: "info" # 로그级别 debug/info/warn/error
file: "" # 로그文件路径,空=출력到stdout
# 启动게이트웨이
./modbus-gateway -config config-tcp2rtu.yaml
# 测试:用pymodbus或QModMaster연결게이트웨이
# 연결주소:게이트웨이IP:502
# 슬레이브ID:1-10(会被路由到RS485시리얼 포트)
# 기능 코드: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:
주소: "0.0.0.0:502"
downstreams:
# 下游1:RS485总线A - 온습도센서(슬레이브1-10)
- type: "rtu"
slave_ids: "1-10"
serial:
device: "/dev/ttyUSB0"
baud_rate: 9600
데이터_bits: 8
parity: "N"
stop_bits: 1
timeout: "500ms"
# 下游2:RS485总线B - 电力仪表(슬레이브11-20)
- type: "rtu"
slave_ids: "11-20"
serial:
device: "/dev/ttyUSB1"
baud_rate: 19200
데이터_bits: 8
parity: "E" # 电力仪表常用짝수 패리티
stop_bits: 1
timeout: "300ms"
# 下游3:Modbus TCP设备 - 变频器(슬레이브21)
- type: "tcp"
slave_ids: "21"
tcp:
주소: "192.168.1.50:502"
# 下游4:本地虚拟슬레이브 - 게이트웨이状态(슬레이브100)
- 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内置了本地虚拟슬레이브功能,可以在没有真实设备的情况下响应Modbus请求,支持三种持久化방식。
# config-local-slave.yaml - 本地虚拟슬레이브설정
gateways:
- name: "local-slave-demo"
upstreams:
- type: "tcp"
tcp:
주소: "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: "/데이터/modbus-slave-101/"
# 虚拟슬레이브3:mmap모드(内存映射文件,高性能+持久化)
- type: "local"
slave_ids: "102"
local:
persistence:
type: "mmap"
path: "/데이터/modbus-slave-102/"
log:
level: "debug"
6.1 三种持久化방식对比
| 방식 | 速度 | 持久化 | 适用시나리오 |
|---|---|---|---|
| memory | 最快 | 否(重启丢失) | 测试、临时模拟 |
| file | 较慢 | 是 | 需要持久化但쓰기不频繁 |
| mmap | 快 | 是 | 生产환경,高频读写 |
七、RTU-over-TCP설정
RTU-over-TCP是将Modbus RTU帧直接封装在TCP中传输(不加MBAP头),常用于某些시리얼 디바이스 서버设备。modbus-gateway支持RTU-over-TCP作为上游或下游。
# config-rtu-over-tcp.yaml - RTU-over-TCP설정
gateways:
- name: "rtu-over-tcp-gateway"
upstreams:
# 上游1:표준Modbus TCP(带MBAP头)
- type: "tcp"
tcp:
주소: "0.0.0.0:502"
# 上游2:RTU-over-TCP(裸RTU帧)
- type: "rtu-over-tcp"
tcp:
주소: "0.0.0.0:503" # 用不同포트区分
downstreams:
# 下游:표준RTU시리얼 포트设备
- type: "rtu"
slave_ids: "1-10"
serial:
device: "/dev/ttyUSB0"
baud_rate: 9600
데이터_bits: 8
parity: "N"
stop_bits: 1
# 下游:RTU-over-TCP设备(如某些시리얼 디바이스 서버)
- type: "rtu-over-tcp"
slave_ids: "11-20"
tcp:
주소: "192.168.1.100:4001" # 시리얼 디바이스 서버주소
log:
level: "info"
八、多게이트웨이实例
单个modbus-gateway进程可以运行多个独立的게이트웨이实例,每个实例有自己的上游监听和下游연결,互不干扰。
# config-multi-gateway.yaml - 多게이트웨이实例
gateways:
# 实例1:车间A게이트웨이
- name: "workshop-a"
upstreams:
- type: "tcp"
tcp:
주소: "0.0.0.0:502"
downstreams:
- type: "rtu"
slave_ids: "1-20"
serial:
device: "/dev/ttyUSB0"
baud_rate: 9600
데이터_bits: 8
parity: "N"
stop_bits: 1
# 实例2:车间B게이트웨이
- name: "workshop-b"
upstreams:
- type: "tcp"
tcp:
주소: "0.0.0.0:503" # 不同포트
downstreams:
- type: "rtu"
slave_ids: "1-20"
serial:
device: "/dev/ttyUSB1"
baud_rate: 19200
데이터_bits: 8
parity: "E"
stop_bits: 1
# 实例3:能源监控게이트웨이
- name: "energy-monitor"
upstreams:
- type: "tcp"
tcp:
주소: "0.0.0.0:504"
downstreams:
- type: "tcp"
slave_ids: "1-5"
tcp:
주소: "192.168.1.50:502"
# 性能分析(可选)
pprof:
enabled: true
주소: "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:
주소: "0.0.0.0:502"
downstreams:
- type: "rtu"
slave_ids: "1-10"
serial:
device: "/dev/ttyUSB0"
baud_rate: 115200
데이터_bits: 8
parity: "N"
stop_bits: 1
timeout: "300ms"
rqst_pause: "50ms"
# RS485 RTS控制
rs485: true # 활성화RTS控制
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芯片的极性
- 常见RS485芯片如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
re시작: 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
- ./데이터:/데이터
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 构建并启动
docker-compose up -d
# 보기로그
docker-compose logs -f
# 重启
docker-compose re시작
十一、完整实战:工厂能源监控게이트웨이
以下是一个完整的生产환경설정案例:工厂能源监控系统,通过modbus-gateway将车间的电力仪表、온습도센서和PLC统一接入SCADA系统。
# factory-energy.yaml - 工厂能源监控게이트웨이
gateways:
- name: "factory-energy-gateway"
upstreams:
# SCADA系统通过TCP연결
- type: "tcp"
tcp:
주소: "0.0.0.0:502"
downstreams:
# 1号RS485总线:电力仪表(슬레이브1-8)
- type: "rtu"
slave_ids: "1-8"
serial:
device: "/dev/ttyUSB0"
baud_rate: 9600
데이터_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总线:온습도센서(슬레이브9-16)
- type: "rtu"
slave_ids: "9-16"
serial:
device: "/dev/ttyUSB1"
baud_rate: 4800
데이터_bits: 8
parity: "N"
stop_bits: 1
timeout: "1000ms"
# 3号RS485总线:PLC(슬레이브17-20)
- type: "rtu"
slave_ids: "17-20"
serial:
device: "/dev/ttyUSB2"
baud_rate: 19200
데이터_bits: 8
parity: "N"
stop_bits: 1
timeout: "300ms"
# 以太网设备:智能电表(슬레이브21)
- type: "tcp"
slave_ids: "21"
tcp:
주소: "192.168.1.50:502"
# 本地虚拟슬레이브:게이트웨이自身状态(슬레이브100)
- type: "local"
slave_ids: "100"
local:
persistence:
type: "mmap"
path: "/데이터/gateway-status/"
# 性能监控
pprof:
enabled: true
주소: "localhost:6060"
log:
level: "info"
file: "/var/log/modbus-gateway/factory-energy.log"
11.1 系统架构설명
- SCADA系统연결게이트웨이TCP 502포트,统一访问所有设备
- 슬레이브1-8的请求路由到USB0(电力仪表,9600짝수 패리티)
- 슬레이브9-16的请求路由到USB1(온습도센서,4800패리티 없음)
- 슬레이브17-20的请求路由到USB2(PLC,19200패리티 없음)
- 슬레이브21的请求转发到以太网智能电表
- 슬레이브100由게이트웨이本地虚拟슬레이브响应,可쓰기게이트웨이运行状态
- 每个下游有独立시퀀스化队列,不会因为一条总线慢而影响其他总线
十二、性能优化与监控
12.1 pprof性能分析
# 활성화pprof后,访问以下端点:
# 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 - 보기CPU占用前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)
- 分批읽기:上位机应尽量批量읽기连续주소,减少请求次数
- 연결复用:上位机保持长연결,避免频繁建立TCP연결
- 슬레이브ID规划:同一总线上的设备使用连续的슬레이브ID,便于路由설정
十三、常见문제与排查
| 문제 | 原因 | 解决方法 |
|---|---|---|
| 上游연결成功但无响应 | 슬레이브ID未일치到任何下游 | 检查slave_ids설정,确保请求的슬레이브ID在路由范围内 |
| RTU设备无响应 | 시리얼 포트 매개변수不일치 | 核对통신 속도、데이터 비트、패리티、정지 비트与设备一致 |
| 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分析,检查上游연결是否正常닫기 |
十四、설정参考速查表
| 설정项 | 유형 | 默认值 | 설명 |
|---|---|---|---|
| gateways[].name | string | - | 게이트웨이名称,用于로그标识 |
| upstreams[].type | enum | - | tcp / rtu / rtu-over-tcp |
| upstreams[].tcp.주소 | string | - | TCP监听주소 |
| downstreams[].type | enum | - | tcp / rtu / rtu-over-tcp / local |
| downstreams[].slave_ids | string | "" | 路由规则,空=일치所有 |
| serial.device | string | - | 시리얼 포트设备路径 |
| serial.baud_rate | int | - | 통신 속도 |
| serial.데이터_bits | int | 8 | 데이터 비트 |
| serial.parity | string | "N" | N/E/O |
| serial.stop_bits | int | 1 | 정지 비트 |
| serial.timeout | duration | "500ms" | 읽기超时 |
| serial.rqst_pause | duration | "100ms" | 请求间最小间隔 |
| serial.rs485 | bool | false | 활성화RTS控制 |
| local.persistence.type | enum | - | memory / file / mmap |
| local.persistence.path | string | - | 持久化目录 |
| pprof.enabled | bool | false | 활성화性能分析 |
| log.level | string | "info" | debug/info/warn/error |
| log.file | string | "" | 로그文件路径 |
十五、학습자료
- 项目주소: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转RTU到多게이트웨이实例、RS485高级控制、Docker部署和完整工厂能源监控的实战설정,可直接用于生产환경部署。建议在部署前先用本地虚拟슬레이브测试路由规则,再逐步接入真实设备。
VIP专属:Go언어Modbus게이트웨이完整代码包
ffutop/modbus-gateway YAML설정驱动,TCP/RTU/本地多프로토콜转换,含工厂能源监控설정。
开通VIP即可下载完整代码,同时解锁 30+ 엔지니어링实战자료包:디버깅스크립트、速查表、项目模板、排查案例……
前往VIP자료库下载 → 月费仅9.9元 / 年费199元