Skip to content

hootrhino/goodmbserver

Repository files navigation

Modbus Server

A comprehensive Modbus server library implemented in Go, supporting both TCP and RTU protocols with flexible storage backends.

Features

  • 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

Supported Function Codes

Read Operations

  • 01 - Read Coils
  • 02 - Read Discrete Inputs
  • 03 - Read Holding Registers
  • 04 - Read Input Registers

Write Operations

  • 05 - Write Single Coil
  • 06 - Write Single Register
  • 15 - Write Multiple Coils
  • 16 - Write Multiple Registers

Installation

go get github.com/hootrhino/goodbusserver

Quick Start

Basic Server Setup

package 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 {}
}

Setting Data

// 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})

Custom Function Handlers

// 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
})

SQLite Storage

// Use SQLite for persistence
store, err := store.NewSqliteStore("modbus.db")
if err != nil {
	log.Fatal(err)
}
defer store.Close()

Configuration

Enhanced Configuration System

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 = 200

Server Options

server := 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)

Environment Variables

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"

Advanced Features

Performance Metrics

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

Middleware System

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.

API Reference

Store Interface

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
}

Error Handling

The library provides comprehensive error handling:

  • ErrIllegalFunction - Invalid function code
  • ErrIllegalDataAddress - Invalid data address
  • ErrIllegalDataValue - Invalid data value
  • ErrServerDeviceFailure - Server device failure

Testing

Run the test suite:

go test -v ./...

Examples

See the examples/ directory for complete working examples:

  • main.go - Basic TCP server
  • advanced_main.go - Full-featured server with all enhancements
  • middleware_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

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.

Changelog

v2.0.0 (Enhanced)

  • 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

v1.0.0

  • Initial release
  • Complete Modbus TCP support
  • In-memory and SQLite storage
  • Comprehensive test coverage
  • Custom handler support

About

Modbus TCP Server

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages