A comprehensive Modbus server library implemented in Go, supporting both TCP and RTU protocols with flexible storage backends.
- Multiple Protocol Support: Modbus TCP and RTU protocols
- Flexible Storage: In-memory and SQLite storage backends
- Standard Function Codes: Complete support for standard Modbus function codes
- Custom Handlers: Extensible callback system for custom function codes
- Concurrent Safe: Thread-safe operations with proper locking
- Configurable: Flexible configuration options with environment variable support
- Production Ready: Comprehensive test coverage and error handling
- Performance Metrics: Built-in metrics collection and reporting
- Timeout Management: Configurable read, write, and idle timeouts
- Middleware Support: Extensible middleware system for request processing
- Graceful Shutdown: Clean shutdown with connection draining
01- Read Coils02- Read Discrete Inputs03- Read Holding Registers04- Read Input Registers
05- Write Single Coil06- Write Single Register15- Write Multiple Coils16- Write Multiple Registers
go get github.com/hootrhino/goodbusserverpackage main
import (
"log"
"github.com/hootrhino/goodbusserver"
"github.com/hootrhino/goodbusserver/store"
)
func main() {
// Create storage backend
store := store.NewInMemoryStore()
// Create and configure server
server := mbserver.NewServer(store)
// Start server
if err := server.Start(":502"); err != nil {
log.Fatal(err)
}
defer server.Stop()
log.Println("Modbus server started on :502")
select {}
}// Set coil data
coils := []byte{0x01, 0x00, 0x01, 0x01}
store.SetCoils(coils)
// Set holding registers
registers := []uint16{1000, 2000, 3000, 4000}
store.SetHoldingRegisters(registers)
// Set coils at specific address
store.SetCoilsAt(100, []byte{0xFF, 0x00})
// Set holding registers at specific address
store.SetHoldingRegistersAt(200, []uint16{1234, 5678})// Register custom function code handler
server.RegisterCustomHandler(0x81, func(request mbserver.Request, store store.Store) ([]byte, error) {
// Custom processing logic
response := []byte{request.FuncCode, 0x01, 0x02}
return response, nil
})// Use SQLite for persistence
store, err := store.NewSqliteStore("modbus.db")
if err != nil {
log.Fatal(err)
}
defer store.Close()Load configuration from environment variables or use defaults:
import "github.com/hootrhino/goodbusserver/config"
// Load from environment variables
cfg, err := config.Load()
if err != nil {
log.Fatal(err)
}
// Or use defaults
cfg := config.DefaultConfig()
cfg.MaxConnections = 200server := mbserver.NewServer(ctx, store, cfg.MaxConnections)
// Configure timeouts
server.SetReadTimeout(30 * time.Second)
server.SetWriteTimeout(30 * time.Second)
server.SetIdleTimeout(60 * time.Second)
// Set logger
server.SetLogger(os.Stdout)
// Set error handler
server.SetErrorHandler(func(err error) {
log.Printf("Server error: %v", err)
})
// Enable metrics
server.EnableMetrics(true)
server.SetMetricsLogger(os.Stdout)
server.StartMetricsReporting(60 * time.Second)MODBUS_SERVER_ADDRESS=":502"
MODBUS_SERVER_MAX_CONNECTIONS="100"
MODBUS_SERVER_READ_TIMEOUT="30s"
MODBUS_SERVER_WRITE_TIMEOUT="30s"
MODBUS_SERVER_IDLE_TIMEOUT="60s"
MODBUS_SERVER_ENABLE_METRICS="true"
MODBUS_SERVER_METRICS_INTERVAL="60s"
MODBUS_SERVER_STORE_TYPE="inmemory" # or "sqlite"
MODBUS_SERVER_SQLITE_DSN="modbus.db"Track server performance in real-time:
// Enable metrics
server.EnableMetrics(true)
server.SetMetricsLogger(os.Stdout)
server.StartMetricsReporting(60 * time.Second)
// Get metrics programmatically
snapshot := server.GetMetrics()
log.Printf("Success Rate: %.2f%%", snapshot.SuccessRate)
log.Printf("Avg Response: %v", snapshot.AvgResponseTime)Metrics include:
- Connection statistics (total, active, rejected)
- Request statistics (total, success rate, failures)
- Response time statistics (avg, min, max)
- Function code usage
- Error counts by type
Extend request processing with middleware:
import "github.com/hootrhino/goodbusserver/middleware"
// Create middleware chain
chain := middleware.Chain(
middleware.RecoveryMiddleware(logger),
middleware.LoggingMiddleware(logger),
middleware.RateLimitMiddleware(100),
middleware.AuthMiddleware([]byte{1, 2, 3}),
middleware.TimeoutMiddleware(5 * time.Second),
)Available middleware:
- Logging: Request/response logging with timing
- Metrics: Automatic metrics collection
- Rate Limiting: Per-connection request rate limiting
- Authentication: Slave ID validation
- Recovery: Panic recovery
- Timeout: Request-level timeouts
See ADVANCED_FEATURES.md for detailed documentation.
type Store interface {
GetCoils(start, quantity uint16) ([]byte, error)
GetDiscreteInputs(start, quantity uint16) ([]byte, error)
GetHoldingRegisters(start, quantity uint16) ([]uint16, error)
GetInputRegisters(start, quantity uint16) ([]uint16, error)
SetCoils(values []byte) error
SetDiscreteInputs(values []byte) error
SetHoldingRegisters(values []uint16) error
SetInputRegisters(values []uint16) error
SetCoilsAt(start uint16, values []byte) error
SetHoldingRegistersAt(start uint16, values []uint16) error
}The library provides comprehensive error handling:
ErrIllegalFunction- Invalid function codeErrIllegalDataAddress- Invalid data addressErrIllegalDataValue- Invalid data valueErrServerDeviceFailure- Server device failure
Run the test suite:
go test -v ./...See the examples/ directory for complete working examples:
main.go- Basic TCP serveradvanced_main.go- Full-featured server with all enhancementsmiddleware_example.go- Middleware usage demonstration
Run examples:
cd examples
go run main.go # Basic example
go run advanced_main.go # Advanced features
go run middleware_example.go # Middleware demo- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.
- ✨ New: Performance metrics system with real-time monitoring
- ✨ New: Configurable timeouts (read, write, idle)
- ✨ New: Middleware system for extensible request processing
- ✨ New: Enhanced configuration with environment variable support
- ✨ New: Graceful shutdown with connection draining
- 📈 Improved: Better error tracking and reporting
- 📈 Improved: Connection management with metrics
- 📚 Docs: Added ADVANCED_FEATURES.md guide
- 📚 Docs: Enhanced examples with advanced features
- Initial release
- Complete Modbus TCP support
- In-memory and SQLite storage
- Comprehensive test coverage
- Custom handler support