All Projects → tbrandon → Mbserver

tbrandon / Mbserver

Licence: mit
Golang Modbus Server (Slave)

Programming Languages

go
31211 projects - #10 most used programming language
golang
3204 projects

Projects that are alternatives of or similar to Mbserver

Qtswissarmyknife
QSAK (Qt Swiss Army Knife) is a multi-functional, cross-platform debugging tool based on Qt.
Stars: ✭ 196 (+58.06%)
Mutual labels:  server, tcp, modbus
Emodbus
Modbus library for both RTU and TCP protocols. Primarily developed on and for ESP32 MCUs.
Stars: ✭ 29 (-76.61%)
Mutual labels:  server, tcp, modbus
Skillbox Chat 08 19
Skillbox demo application for the Python course
Stars: ✭ 25 (-79.84%)
Mutual labels:  server, tcp
Tinytcpserver
A small tcp server working under Mono or .NET (4.0) and provides hooks for handling data exchange with clients (works under mono and .net). Behaviour/protocol/reaction could be specified via custom C# script.
Stars: ✭ 14 (-88.71%)
Mutual labels:  server, tcp
Tcpbin
Very crude and poorly written HTTP(s) and SMTP bin
Stars: ✭ 85 (-31.45%)
Mutual labels:  server, tcp
Laravel S
LaravelS is an out-of-the-box adapter between Swoole and Laravel/Lumen.
Stars: ✭ 3,479 (+2705.65%)
Mutual labels:  server, tcp
Simps
🚀 A simple, lightweight and high-performance PHP coroutine framework.
Stars: ✭ 318 (+156.45%)
Mutual labels:  server, tcp
Zeus
A high performance, cross-platform Internet Communication Engine. Developed with native socket API. Aim at handling millions of concurrent connections.
Stars: ✭ 30 (-75.81%)
Mutual labels:  server, tcp
Simplenetwork
simple TCP server / client C++ linux socket
Stars: ✭ 225 (+81.45%)
Mutual labels:  server, tcp
Deta cache
缓存cache服务器
Stars: ✭ 106 (-14.52%)
Mutual labels:  server, tcp
Simpletcp
Simple wrapper for TCP client and server in C# with SSL support
Stars: ✭ 99 (-20.16%)
Mutual labels:  server, tcp
Modbuspp
A C++ Library for Modbus TCP Protocol
Stars: ✭ 108 (-12.9%)
Mutual labels:  tcp, modbus
Iotclient
这是一个物联网设备通讯协议实现客户端,将会包括主流PLC通信读取、ModBus协议、Bacnet协议等常用工业通讯协议。本组件终身开源免费,采用最宽松的MIT开源协议,您可以随意修改和商业使用(商业使用请做好评估和测试)。
Stars: ✭ 311 (+150.81%)
Mutual labels:  tcp, modbus
node-drivers
Industrial protocol drivers in node.js
Stars: ✭ 20 (-83.87%)
Mutual labels:  tcp, modbus
Networksocket
NetworkSocket是一个以中间件(middleware)扩展通讯协议,以插件(plug)扩展服务器功能的支持SSL安全传输的通讯框架;目前支持http、websocket、fast、flex策略与silverlight策略协议。
Stars: ✭ 435 (+250.81%)
Mutual labels:  server, tcp
Modbus-STM32-HAL-FreeRTOS
Modbus TCP and RTU, Master and Slave for STM32 using Cube HAL and FreeRTOS
Stars: ✭ 272 (+119.35%)
Mutual labels:  tcp, modbus
Xtcp
A TCP Server Framework with graceful shutdown, custom protocol.
Stars: ✭ 116 (-6.45%)
Mutual labels:  server, tcp
Watsontcp
WatsonTcp is the easiest way to build TCP-based clients and servers in C#.
Stars: ✭ 209 (+68.55%)
Mutual labels:  server, tcp
Pss
This is a based plug-in framework that provides cross-platform IO and logically separated plug-in services.
Stars: ✭ 219 (+76.61%)
Mutual labels:  server, tcp
Proxy
C++ TCP Proxy Server
Stars: ✭ 98 (-20.97%)
Mutual labels:  server, tcp

Build Status Coverage Status GoDoc Software License

Golang Modbus Server (Slave)

The Golang Modbus Server (Slave) responds to the following Modbus function requests:

Bit access:

  • Read Discrete Inputs
  • Read Coils
  • Write Single Coil
  • Write Multiple Coils

16-bit acess:

  • Read Input Registers
  • Read Multiple Holding Registers
  • Write Single Holding Register
  • Write Multiple Holding Registers

TCP and serial RTU access is supported.

The server internally allocates memory for 65536 coils, 65536 discrete inputs, 653356 holding registers and 65536 input registers. On start, all values are initialzied to zero. Modbus requests are processed in the order they are received and will not overlap/interfere with each other.

The golang mbserver documentation.

Example Modbus TCP Server

Create a Modbus TCP Server (Slave):

package main

import (
	"log"
	"time"

	"github.com/tbrandon/mbserver"
)

func main() {
	serv := mbserver.NewServer()
	err := serv.ListenTCP("127.0.0.1:1502")
	if err != nil {
		log.Printf("%v\n", err)
	}
	defer serv.Close()

	// Wait forever
	for {
		time.Sleep(1 * time.Second)
	}
}

The server will continue to listen until killed (<ctrl>-c). Modbus typically uses port 502 (standard users require special permissions to listen on port 502). Change the port number as required. Change the address to 0.0.0.0 to listen on all network interfaces.

An example of a client writing and reading holding regsiters:

package main

import (
	"fmt"

	"github.com/goburrow/modbus"
)

func main() {
	handler := modbus.NewTCPClientHandler("localhost:1502")
	// Connect manually so that multiple requests are handled in one session
	err := handler.Connect()
	defer handler.Close()
	client := modbus.NewClient(handler)

	_, err = client.WriteMultipleRegisters(0, 3, []byte{0, 3, 0, 4, 0, 5})
	if err != nil {
		fmt.Printf("%v\n", err)
	}

	results, err := client.ReadHoldingRegisters(0, 3)
	if err != nil {
		fmt.Printf("%v\n", err)
	}
	fmt.Printf("results %v\n", results)
}

Outputs:
results [0 3 0 4 0 5]

Example Listening on Multiple TCP Ports and Serial Devices

The Golang Modbus Server can listen on multiple TCP ports and serial devices. In the following example, the Modbus server will be configured to listen on 127.0.0.1:1502, 0.0.0.0:3502, /dev/ttyUSB0 and /dev/ttyACM0

	serv := mbserver.NewServer()
	err := serv.ListenTCP("127.0.0.1:1502")
	if err != nil {
		log.Printf("%v\n", err)
	}

	err := serv.ListenTCP("0.0.0.0:3502")
	if err != nil {
		log.Printf("%v\n", err)
	}

	err := s.ListenRTU(&serial.Config{
		Address:  "/dev/ttyUSB0",
		BaudRate: 115200,
		DataBits: 8,
		StopBits: 1,
		Parity:   "N",
		Timeout:  10 * time.Second})
	if err != nil {
		t.Fatalf("failed to listen, got %v\n", err)
	}

	err := s.ListenRTU(&serial.Config{
		Address:  "/dev/ttyACM0",
		BaudRate: 9600,
		DataBits: 8,
		StopBits: 1,
		Parity:   "N",
		Timeout:  10 * time.Second,
		RS485: serial.RS485Config{
			Enabled: true,
			DelayRtsBeforeSend: 2 * time.Millisecond
			DelayRtsAfterSend: 3 * time.Millisecond
			RtsHighDuringSend: false,
			RtsHighAfterSend: false,
			RxDuringTx: false
			})
	if err != nil {
		t.Fatalf("failed to listen, got %v\n", err)
	}

	defer serv.Close()

Information on serial port settings.

Server Customization

RegisterFunctionHandler allows the default server functionality to be overridden for a Modbus function code.

func (s *Server) RegisterFunctionHandler(funcCode uint8, function func(*Server, Framer) ([]byte, *Exception))

Example of overriding the default ReadDiscreteInputs funtion:

serv := NewServer()

// Override ReadDiscreteInputs function.
serv.RegisterFunctionHandler(2,
    func(s *Server, frame Framer) ([]byte, *Exception) {
        register, numRegs, endRegister := frame.registerAddressAndNumber()
        // Check the request is within the allocated memory
        if endRegister > 65535 {
            return []byte{}, &IllegalDataAddress
        }
        dataSize := numRegs / 8
        if (numRegs % 8) != 0 {
            dataSize++
        }
        data := make([]byte, 1+dataSize)
        data[0] = byte(dataSize)
        for i := range s.DiscreteInputs[register:endRegister] {
            // Return all 1s, regardless of the value in the DiscreteInputs array.
            shift := uint(i) % 8
            data[1+i/8] |= byte(1 << shift)
        }
        return data, &Success
    })

// Start the server.
err := serv.ListenTCP("localhost:4321")
if err != nil {
    log.Printf("%v\n", err)
    return
}
defer serv.Close()

// Wait for the server to start
time.Sleep(1 * time.Millisecond)

// Example of a client reading from the server started above.
// Connect a client.
handler := modbus.NewTCPClientHandler("localhost:4321")
err = handler.Connect()
if err != nil {
    log.Printf("%v\n", err)
    return
}
defer handler.Close()
client := modbus.NewClient(handler)

// Read discrete inputs.
results, err := client.ReadDiscreteInputs(0, 16)
if err != nil {
    log.Printf("%v\n", err)
}

fmt.Printf("results %v\n", results)

Output:

results [255 255]

Benchmarks

Quanitify server read/write performance. Benchmarks are for Modbus TCP operations.

Run benchmarks:

$ go test -bench=.
BenchmarkModbusWrite1968MultipleCoils-8            50000             30912 ns/op
BenchmarkModbusRead2000Coils-8                     50000             27875 ns/op
BenchmarkModbusRead2000DiscreteInputs-8            50000             27335 ns/op
BenchmarkModbusWrite123MultipleRegisters-8        100000             22655 ns/op
BenchmarkModbusRead125HoldingRegisters-8          100000             21117 ns/op
PASS

Operations per second are higher when requests are not forced to be synchronously processed. In the case of simultaneous client access, synchronous Modbus request processing prevents data corruption.

To understand performanc limitations, create a CPU profile graph for the WriteMultipleCoils benchmark:

go test -bench=.MultipleCoils -cpuprofile=cpu.out
go tool pprof modbus-server.test cpu.out
(pprof) web

Race Conditions

There is a known race condition in the code relating to calling Serial Read() and Close() functions in different go routines.

To check for race conditions, run:

go test --race
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].