Skip to main content

TCP Server

Each TCP server instance is capable of processing requests for one or more unit IDs from multiple external clients.

graph TD A[Client #1] --> D[Modbus TCP Server] B[Client #2] --> D C[Client #3] --> D subgraph Application D --> E[UNIT ID 0x01] D --> F[UNIT ID 0x02] end

The DeviceMap class is used to build the association between unit IDs and the custom read/write functionality you wish to provide to clients.

Creating a server

To create a server, first build a DeviceMap for each unit ID that the server will answer. Then use the create_tcp_server static method of the Server class. The created server will start listening on the port immediately.

The Server.CreateTcp method takes the following arguments:

  • runtime: tokio runtime used to drive the async process. See Runtime for more details.
  • address: IP address of the adapter on which to listen. It may be any specified as any valid IPv4 or IPv6 local endpoint, such as:
    • 127.0.0.1 for localhost only
    • 0.0.0.0 for all adapters
    • The IP address for a particular adapter
  • port: port on which to listen for connection
  • filter: AddressFilter which can be used to limit which external IPs may connect.
  • max_sessions: maximum concurrent sessions allowed by the server. When the maximum number of sessions is reached, a new connection will end the oldest session in order to limit resource usage.
  • map: Map of unit ids and their corresponding callback handlers.
let handler =
SimpleHandler::new(vec![false; 10], vec![false; 10], vec![0; 10], vec![0; 10]).wrap();

// map unit ids to a handler for processing requests
let map = ServerHandlerMap::single(UnitId::new(1), handler.clone());

let server = rodbus::server::spawn_tcp_server_task(
1,
"127.0.0.1:502".parse()?,
map,
AddressFilter::Any,
DecodeLevel::default(),
)
.await?;
tip

In Rust, you can easily wrap your RequestHandler implementation in a Arc<Mutex> using the wrap() default implementation.