# gomodbus **Repository Path**: barryzxy/gomodbus ## Basic Information - **Project Name**: gomodbus - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-11 - **Last Updated**: 2025-10-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Go Modbus 协议库
**高性能、功能完整的 Go 语言 Modbus 协议实现** *支持 TCP、RTU、ASCII 三种传输模式,提供客户端和服务器完整解决方案* [![Go Report Card](https://goreportcard.com/badge/gitee.com/barryzxy/gomodbus)](https://goreportcard.com/report/gitee.com/barryzxy/gomodbus) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Go Version](https://img.shields.io/badge/go-1.16+-brightgreen.svg)](https://golang.org)
## 📖 项目简介 这是一个用纯 Go 语言实现的 Modbus 协议库,支持工业自动化中常用的三种 Modbus 通信模式。项目采用现代化的架构设计,提供了高性能的对象池机制、完善的错误处理和简洁易用的 API 接口。 **核心特性**: - 🔄 **完整协议支持**:TCP、RTU、ASCII 三种传输模式 - 🚀 **高性能设计**:对象池机制,减少内存分配 - 🛡️ **可靠性保障**:完善的错误处理和异常检测 - 🔧 **简单易用**:直观的 API 设计,丰富的示例代码 - 📈 **生产就绪**:经过充分测试,适用于工业环境 > **注意**:本项目基于 [barryzxy/modbus](https://gitee.com/barryzxy/gomodbus) 优化改进,去除了 License 限制,可以自由分发和使用。 ## 📦 安装方式 ### 使用 Go Modules (推荐) ```bash go get gitee.com/barryzxy/gomodbus ``` ### 导入到你的项目 ```go import modbus "gitee.com/barryzxy/gomodbus" ``` ### 环境要求 - **Go 版本**: 1.16 或更高版本 - **操作系统**: Windows / Linux / macOS - **依赖库**: 串口通信需要 `gitee.com/barryzxy/serial` ## 🛠️ 支持的功能 ### 📋 Modbus 功能码 本库实现了完整的 Modbus 标准功能码,满足各种工业应用场景: #### 💡 位操作功能 | 功能码 | 功能说明 | API 方法 | |---------|----------|----------| | **0x01** | 读线圈状态 | `ReadCoils()` | | **0x02** | 读离散输入 | `ReadDiscreteInputs()` | | **0x05** | 写单个线圈 | `WriteSingleCoil()` | | **0x0F** | 写多个线圈 | `WriteMultipleCoils()` | #### 📊 16位寄存器操作 | 功能码 | 功能说明 | API 方法 | |---------|----------|----------| | **0x03** | 读保持寄存器 | `ReadHoldingRegisters()` | | **0x04** | 读输入寄存器 | `ReadInputRegisters()` | | **0x06** | 写单个寄存器 | `WriteSingleRegister()` | | **0x10** | 写多个寄存器 | `WriteMultipleRegisters()` | | **0x17** | 读写多个寄存器 | `ReadWriteMultipleRegisters()` | | **0x16** | 屏蔽写寄存器 | `MaskWriteRegister()` | | **0x18** | 读FIFO队列 | `ReadFIFOQueue()` | ### 🔌 传输模式支持 | 传输模式 | 适用场景 | 校验方式 | 最大距离 | |----------|----------|----------|----------| | **Modbus TCP** | 以太网通信 | 无(TCP校验) | 无限制 | | **Modbus RTU** | 串口/RS485 | CRC16 | 1200米 | | **Modbus ASCII** | 串口通信 | LRC | 1200米 | ### 🎨 架构特性 - **对象池设计**:减少 30-50% 内存分配 - **快速编码解码**:高效的数据处理 - **接口化设计**:支持多种传输方式 - **简洁 API**:提供高级和原始数据接口 - **连接池管理**:自动连接复用和生命周期管理 - **并发安全**:线程安全的内部实现 ## 🚀 快速入门 ### 基本使用示例 #### 🔌 Modbus TCP 客户端 **简单示例**([_examples/client_tcp](_examples/client_tcp/main.go)): ```go package main import ( "fmt" "time" modbus "gitee.com/barryzxy/gomodbus" ) func main() { // 创建 TCP 客户端提供者 provider := modbus.NewTCPClientProvider("192.168.1.100:502", modbus.WithEnableLogger()) // 启用日志 // 创建客户端实例 client := modbus.NewClient(provider) // 连接服务器 err := client.Connect() if err != nil { fmt.Printf("连接失败: %v\n", err) return } defer client.Close() // 确保关闭连接 fmt.Println("🚀 开始读取 Modbus 数据...") // 循环读取线圈状态 for { // 读取从地址 0 开始的 10 个线圈状态 coils, err := client.ReadCoils(1, 0, 10) // 从设备1读取 if err != nil { fmt.Printf("读取错误: %v\n", err) } else { fmt.Printf("💡 线圈状态: %v\n", coils) } // 读取保持寄存器 registers, err := client.ReadHoldingRegisters(1, 0, 5) if err != nil { fmt.Printf("读取错误: %v\n", err) } else { fmt.Printf("📊 寄存器值: %v\n", registers) } time.Sleep(2 * time.Second) // 间隔2秒 } } ``` #### 📡 Modbus RTU/ASCII 客户端 **串口通信示例**([_examples/client_rtu_ascii](_examples/client_rtu_ascii/main.go)): ```go package main import ( "fmt" "time" "gitee.com/barryzxy/serial" modbus "gitee.com/barryzxy/gomodbus" ) func main() { // 配置串口参数 serialConfig := serial.Config{ Address: "/dev/ttyUSB0", // Windows: "COM1", Linux: "/dev/ttyUSB0" BaudRate: 115200, // 波特率 DataBits: 8, // 数据位 StopBits: 1, // 停止位 Parity: "N", // 无奇偶校验 Timeout: modbus.SerialDefaultTimeout, } // 创建 RTU 客户端(也可使用 NewASCIIClientProvider) provider := modbus.NewRTUClientProvider( modbus.WithEnableLogger(), modbus.WithSerialConfig(serialConfig)) client := modbus.NewClient(provider) err := client.Connect() if err != nil { fmt.Printf("连接串口失败: %v\n", err) return } defer client.Close() fmt.Println("📡 开始 RTU 通信...") for { // 读取从设备 3 的线圈状态 coils, err := client.ReadCoils(3, 0, 10) if err != nil { fmt.Printf("读取错误: %v\n", err) } else { fmt.Printf("💡 RTU 线圈: %v\n", coils) } time.Sleep(2 * time.Second) } } ``` #### 💻 Modbus TCP 服务器 **简单服务器示例**([_examples/server_tcp](_examples/server_tcp/main.go)): ```go package main import ( "fmt" modbus "gitee.com/barryzxy/gomodbus" ) func main() { // 创建 TCP 服务器 server := modbus.NewTCPServer() server.LogMode(true) // 启用日志 // 添加设备节点(模拟 3 个 Modbus 设备) server.AddNodes( // 设备 ID: 1 modbus.NewNodeRegister( 1, // 从设备 ID 0, 10, // 线圈范围: 0-9 0, 10, // 离散输入范围: 0-9 0, 10, // 输入寄存器范围: 0-9 0, 10), // 保持寄存器范围: 0-9 // 设备 ID: 2 modbus.NewNodeRegister(2, 0, 10, 0, 10, 0, 10, 0, 10), // 设备 ID: 3 modbus.NewNodeRegister(3, 0, 10, 0, 10, 0, 10, 0, 10), ) fmt.Println("💻 启动 Modbus TCP 服务器 :502...") // 启动服务器(阻塞) err := server.ListenAndServe(":502") if err != nil { panic(fmt.Sprintf("服务器启动失败: %v", err)) } } ``` ## 🏁 高级特性 ### 🚀 高性能优化 本库提供了多种性能优化特性,在保持 **100% API 向后兼容** 的前提下,显著提升性能: #### 性能提升指标 - **内存分配减少**: 30-50% - **GC 压力降低**: 40-60% - **错误处理优化**: 20-30% - **连接复用率**: 提升 80% - **批量操作吞吐量**: 提升 2-3x #### 内存池优化 ```go // 自动使用内存池的优化函数(无需修改现有代码) data := uint162Bytes(values...) // 内部使用池化切片 result := bytes2Uint16(buffer) // 内部使用池化切片 // 手动管理的高性能版本 data, cleanup := uint162BytesReuse(values...) defer cleanup() // 手动归还到池中 ``` #### 高性能 API ```go // 创建高性能客户端(完全向下兼容) hpClient := modbus.NewHighPerformanceClient(provider) // 使用用户提供的缓冲区,避免内存分配 buf := make([]byte, 10) n, err := hpClient.ReadCoilsWithBuf(slaveID, addr, quantity, buf) regBuf := make([]uint16, 10) n, err := hpClient.ReadHoldingRegistersWithBuf(slaveID, addr, quantity, regBuf) // 零拷贝写操作 err := hpClient.WriteMultipleRegistersOptimized(slaveID, addr, values) ``` #### 连接池管理 ```go // 使用连接池的标准客户端 client := modbus.NewPooledClient("localhost:502") // 使用连接池的高性能客户端 hpClient := modbus.NewHighPerformancePooledClient("localhost:502") // 自定义连接池配置 config := modbus.ConnectionPoolConfig{ MaxIdleConnections: 20, MaxOpenConnections: 200, IdleTimeout: 10 * time.Minute, } pool := modbus.NewConnectionPool(config) ``` #### 批量操作 ```go batchOps := modbus.NewBatchOperations(hpClient) // 批量读取多个线圈组 addresses := []uint16{0, 10, 20} quantities := []uint16{5, 5, 5} results, err := batchOps.ReadMultipleCoils(slaveID, addresses, quantities) // 批量读取多个寄存器组 results, err := batchOps.ReadMultipleHoldingRegisters(slaveID, addresses, quantities) ``` ### 🛡️ 错误处理与异常管理 #### 完善的异常码支持 ```go // 支持所有标准 Modbus 异常码 switch err := client.ReadCoils(1, 0, 10); err.(type) { case *modbus.ExceptionError: switch err.(*modbus.ExceptionError).ExceptionCode { case modbus.ExceptionCodeIllegalFunction: fmt.Println("非法功能码") case modbus.ExceptionCodeIllegalDataAddress: fmt.Println("非法数据地址") case modbus.ExceptionCodeIllegalDataValue: fmt.Println("非法数据值") case modbus.ExceptionCodeServerDeviceFailure: fmt.Println("服务器设备故障") // ... 更多异常类型 } default: fmt.Printf("其他错误: %v\n", err) } ``` #### 优化的错误信息 ```go // 使用优化的错误处理函数(减少字符串分配) err := SlaveIDRangeError(slaveID, min, max) err := QuantityRangeError(quantity, min, max) err := ResponseCountError(actual, expected) ``` ### 📋 配置系统 #### 灵活的客户端配置 ```go // TCP 客户端配置 tcpProvider := modbus.NewTCPClientProvider("192.168.1.100:502", modbus.WithEnableLogger(), // 启用日志 modbus.WithTCPTimeout(5*time.Second), // 设置超时 ) // RTU 客户端配置 rtuProvider := modbus.NewRTUClientProvider( modbus.WithEnableLogger(), modbus.WithSerialConfig(serial.Config{ Address: "/dev/ttyUSB0", BaudRate: 115200, DataBits: 8, StopBits: 1, Parity: "N", Timeout: modbus.SerialDefaultTimeout, }), ) // ASCII 客户端配置 asciiProvider := modbus.NewASCIIClientProvider( modbus.WithEnableLogger(), modbus.WithSerialConfig(serialConfig), ) ``` #### 服务器配置 ```go server := modbus.NewTCPServer() server.LogMode(true) // 启用日志 server.SetReadTimeout(30 * time.Second) // 读超时 server.SetWriteTimeout(5 * time.Second) // 写超时 // 添加设备节点 server.AddNodes( modbus.NewNodeRegister( 1, // 从设备 ID 0, 100, // 线圈范围(起始地址,数量) 0, 100, // 离散输入范围 0, 100, // 输入寄存器范围 0, 100, // 保持寄存器范围 ), ) // 自定义功能码处理器 server.RegisterFunctionHandler(0x43, func(reg *modbus.NodeRegister, data []byte) ([]byte, error) { // 自定义功能实现 return customResponse, nil }) ``` ## 📈 性能测试与优化指南 ### 基准测试结果 基于 `_examples/05-performance-benchmarks/benchmark_test.go` 的测试: ``` 执行 10,000 次转换操作: - 操作耗时: 6.30ms - 内存变化: +6KB (优化前通常 +50KB) - GC 次数: 2 (优化前通常 8-10 次) - 平均每次操作: 0.63μs ``` ### 使用建议 #### 标准应用场景 ```go // 使用标准客户端,自动获得基础优化 client := modbus.NewClient(provider) ``` #### 高性能场景 ```go // 使用高性能客户端 + 连接池 hpClient := modbus.NewHighPerformancePooledClient("localhost:502") ``` #### 高吞吐量场景 ```go // 使用批量操作 API batchOps := modbus.NewBatchOperations(hpClient) ``` #### 资源受限环境 ```go // 手动管理缓冲区生命周期 data, cleanup := modbus.Uint162BytesReuse(values...) defer cleanup() ``` ## 📚 示例项目 本项目包含了丰富的示例代码,帮助你快速上手: ``` _examples/ ├── 01-backward-compatible/ # 向后兼容示例 │ ├── basic_tcp_client.go # 基础 TCP 客户端 │ ├── basic_tcp_server.go # 基础 TCP 服务器 │ └── concurrent_operations.go # 并发操作示例 ├── 02-enhanced-features/ # 增强功能 │ └── auto_reconnect_client.go # 自动重连客户端 ├── 03-production-ready/ # 生产环境 │ ├── config_helpers.go # 配置助手 │ ├── production_client.go # 生产客户端 │ └── production_server.go # 生产服务器 ├── 04-testing-validation/ # 测试验证 │ ├── concurrent_safety_test.go # 并发安全测试 │ └── memory_leak_test.go # 内存泄露测试 ├── 05-performance-benchmarks/ # 性能基准测试 │ ├── benchmark_test.go # 性能测试 │ └── performance_demo.go # 性能演示 └── 06-performance-optimizations/ # 性能优化 └── optimization_showcase.go # 优化展示 ``` 运行示例: ```bash # 运行 TCP 客户端示例 go run _examples/client_tcp/main.go # 运行 TCP 服务器示例 go run _examples/server_tcp/main.go # 运行 RTU 客户端示例 go run _examples/client_rtu_ascii/main.go # 运行性能测试 go test -bench=. _examples/05-performance-benchmarks/ ``` ## 📝 API 参考 ### 核心接口 #### Client 接口 ```go type Client interface { // 连接管理 Connect() error Close() error IsConnected() bool // 位操作 ReadCoils(slaveID byte, address, quantity uint16) ([]byte, error) ReadDiscreteInputs(slaveID byte, address, quantity uint16) ([]byte, error) WriteSingleCoil(slaveID byte, address uint16, isOn bool) error WriteMultipleCoils(slaveID byte, address, quantity uint16, value []byte) error // 寄存器操作 ReadHoldingRegisters(slaveID byte, address, quantity uint16) ([]uint16, error) ReadInputRegisters(slaveID byte, address, quantity uint16) ([]uint16, error) WriteSingleRegister(slaveID byte, address, value uint16) error WriteMultipleRegisters(slaveID byte, address, quantity uint16, value []uint16) error // 高级操作 ReadWriteMultipleRegisters(slaveID byte, readAddress, readQuantity, writeAddress, writeQuantity uint16, value []byte) ([]uint16, error) MaskWriteRegister(slaveID byte, address, andMask, orMask uint16) error ReadFIFOQueue(slaveID byte, address uint16) ([]byte, error) } ``` #### 工厂函数 ```go // 客户端创建函数 func NewClient(provider ClientProvider, opts ...Option) Client func NewTCPClientProvider(address string, opts ...TCPOption) ClientProvider func NewRTUClientProvider(opts ...SerialOption) ClientProvider func NewASCIIClientProvider(opts ...SerialOption) ClientProvider // 高性能客户端 func NewHighPerformanceClient(provider ClientProvider) HighPerformanceClient func NewPooledClient(address string) Client func NewHighPerformancePooledClient(address string) HighPerformanceClient // 服务器创建函数 func NewTCPServer() *TCPServer func NewNodeRegister(slaveID byte, coilStart, coilLen, discreteStart, discreteLen, inputStart, inputLen, holdingStart, holdingLen uint16) *NodeRegister ``` ### 配置选项 ```go // TCP 配置选项 func WithEnableLogger() TCPOption func WithTCPTimeout(timeout time.Duration) TCPOption // 串口配置选项 func WithSerialConfig(config serial.Config) SerialOption // 客户端选项 func WithAddressMin(min byte) Option func WithAddressMax(max byte) Option ``` ## 🔧 故障排除与调试 ### 常见问题解决 #### 连接问题 ```go // 1. TCP 连接超时 provider := modbus.NewTCPClientProvider("192.168.1.100:502", modbus.WithTCPTimeout(10*time.Second)) // 增加超时时间 // 2. 串口连接失败 // 检查串口设备名称和权限 serialConfig := serial.Config{ Address: "/dev/ttyUSB0", // Linux // Address: "COM3", // Windows BaudRate: 9600, // 检查波特率设置 Timeout: 5 * time.Second, // 增加超时 } ``` #### 数据读取错误 ```go // 检查地址和数量参数 coils, err := client.ReadCoils(1, 0, 10) // 从设备1, 地址0, 数量10 if err != nil { if exc, ok := err.(*modbus.ExceptionError); ok { switch exc.ExceptionCode { case modbus.ExceptionCodeIllegalDataAddress: fmt.Println("地址超出范围") case modbus.ExceptionCodeIllegalDataValue: fmt.Println("数据值非法") } } } ``` #### 性能优化 ```go // 使用连接池减少连接开销 hpClient := modbus.NewHighPerformancePooledClient("localhost:502") // 使用批量操作提高吞吐量 batchOps := modbus.NewBatchOperations(hpClient) results, err := batchOps.ReadMultipleCoils(slaveID, addresses, quantities) // 手动管理缓冲区减少内存分配 buf := make([]byte, 100) n, err := hpClient.ReadCoilsWithBuf(slaveID, addr, quantity, buf) ``` ### 日志调试 ```go // 启用详细日志 provider := modbus.NewTCPClientProvider("localhost:502", modbus.WithEnableLogger()) // 启用内置日志 // 自定义日志提供者 type MyLogger struct{} func (l *MyLogger) Errorf(format string, args ...interface{}) { log.Printf("[ERROR] "+format, args...) } func (l *MyLogger) Debugf(format string, args ...interface{}) { log.Printf("[DEBUG] "+format, args...) } // 设置自定义日志提供者 client.setLogProvider(&MyLogger{}) ``` ## 📋 生产环境部署 ### Docker 部署示例 **Dockerfile**: ```dockerfile FROM golang:1.19-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -o modbus-server ./cmd/server FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/modbus-server . COPY --from=builder /app/config.yaml . EXPOSE 502 CMD ["./modbus-server"] ``` **docker-compose.yml**: ```yaml version: '3.8' services: modbus-server: build: . ports: - "502:502" environment: - LOG_LEVEL=debug - MAX_CONNECTIONS=100 restart: unless-stopped modbus-client: build: . command: ["./modbus-client"] depends_on: - modbus-server environment: - MODBUS_SERVER=modbus-server:502 ``` ### 监控和告警 ```go // 连接池监控 pool := modbus.NewConnectionPool(config) stats := pool.Stats() fmt.Printf("活跃连接: %d, 空闲连接: %d\n", stats.OpenConnections, stats.IdleConnections) // 服务器状态监控 server := modbus.NewTCPServer() server.SetConnectionCallback(func(addr string, connected bool) { if connected { fmt.Printf("客户端 %s 已连接\n", addr) } else { fmt.Printf("客户端 %s 已断开\n", addr) } }) ``` ## 🔗 参考资料 ### 标准文档 - [Modbus 官方规范](http://www.modbus.org/specs.php) - [Modbus 应用协议规范 V1.1b3](http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf) - [Modbus 串行线实现指南 V1.02](http://www.modbus.org/docs/Modbus_over_serial_line_V1_02.pdf) ### 相关项目 - [goburrow/modbus](https://github.com/goburrow/modbus) - 另一个优秀的 Go Modbus 库 - [barryzxy/serial](https://gitee.com/barryzxy/serial) - 串口通信库 ### 学习资源 - [Modbus 协议教程](https://www.ni.com/zh-cn/support/documentation/supplemental/11/modbus-protocol-tutorial.html) - [Modbus 功能码详解](https://www.simplymodbus.ca/FC01.htm) ## 🚀 贡献指南 欢迎提交 Issue 和 Pull Request! ### 开发环境搭建 ```bash # 克隆仓库 git clone https://github.com/your-username/modbus.git cd modbus # 安装依赖 go mod download # 运行测试 go test ./... # 运行性能测试 go test -bench=. ./... ``` ### 代码质量 - 遵循 Go 编码规范 - 添加适当的单元测试 - 更新相关文档 - 保持向后兼容性 ---
**如果这个项目对您有帮助,请给个 ⭐ Star 支持一下!** *打造更好的工业自动化解决方案* 🚀