TCP server
Bind one or more outstation instances to a TCP server using an AddressFilter. Unlike most server protocols, each outstation can only communicate with one client at a time because DNP3 maintains event data for a specific master. To support multiple masters on the same port, preconfigure each master IP address and associate it with a specific outstation instance.
Creating a server
Create a TCPServer instance. Creating a server doesn't initiate bind/listen immediately. Specify endpoints as <address>:<port> where address is any valid IPv4 or IPv6 local endpoint:
127.0.0.1for localhost only0.0.0.0for all adapters- The IP address for a particular adapter
- Rust
- C
- C++
- Java
- C#
let server = Server::new_tcp_server(LinkErrorMode::Close, endpoint);
dnp3_outstation_server_t *server = NULL;
dnp3_param_error_t err = dnp3_outstation_server_create_tcp_server(runtime, DNP3_LINK_ERROR_MODE_CLOSE, endpoint, &server);
// check error
auto server = OutstationServer::create_tcp_server(runtime, LinkErrorMode::close, endpoint);
OutstationServer server = OutstationServer.createTcpServer(runtime, LinkErrorMode.CLOSE, endpoint);
var server = OutstationServer.CreateTcpServer(runtime, LinkErrorMode.Close, endpoint);
LinkErrorMode controls what will happen if a malformed link-layer frame is received. Typically, it will close the socket to prevent transmission of corrupted data. However, you can set this value to Discard if you want the parser to discard errors and search for the start of the next frame. This behavior is required if you're connecting to a terminal server that bridges TCP to a serial port.
Adding outstations
You can now associate one or more outstations with the TCPServer. The TcpServer::addOutstation method takes all the components discussed in previous sections, followed by an AddressFilter. This filter determines which masters are allowed to associate with a specific outstation.
If the filter allows the same address(es) as an existing outstation's filter, then TcpServer::addOutstation will fail.
- Rust
- C
- C++
- Java
- C#
let outstation = server.add_outstation(
get_outstation_config_from_cli(cli),
Box::new(ExampleOutstationApplication::new()),
Box::new(ExampleOutstationInformation),
Box::new(ExampleControlHandler),
LogListener::create("connection"),
AddressFilter::Any,
)?;
The Rust add_outstation method spawns the outstation onto the Tokio runtime, so it must be called from within the runtime. Use add_outstation_no_spawn if you want to spawn the returned future yourself.
dnp3_address_filter_t *address_filter = dnp3_address_filter_any();
dnp3_param_error_t err = dnp3_outstation_server_add_outstation(
server,
get_outstation_config(),
get_outstation_application(),
get_outstation_information(),
get_control_handler(),
get_connection_state_listener(),
address_filter,
&outstation
);
dnp3_address_filter_destroy(address_filter);
// check error
auto filter = AddressFilter::any();
auto outstation = server.add_outstation(
get_outstation_config(),
create_outstation_application(),
create_outstation_information(),
create_control_handler(),
connection_state_listener([](ConnectionState state) { std::cout << "connection state: " << to_string(state) << std::endl; }),
filter
);
// check error
final Outstation outstation =
server.addOutstation(
getOutstationConfig(),
new ExampleOutstationApplication(),
new ExampleOutstationInformation(),
new ExampleControlHandler(),
state -> System.out.println("connection state: " + state),
AddressFilter.any());
var outstation = server.AddOutstation(
GetOutstationConfig(),
new ExampleOutstationApplication(),
new ExampleOutstationInformation(),
new ExampleControlHandler(),
new LogListener("connection"),
AddressFilter.Any()
);
The examples above use AddressFilter.any() which allows any master IP to connect.
If you've already connected a master to the outstation and another matching IP address tries to connect, the existing connection will close. The outstation will then begin a communication session with the new master.
The AddressFilter constructor accepts IPv4 wildcards (e.g. 192.168.0.*) which are convenient when you want to allow any master IP in a subnet to connect to the outstation.
ConnectionStateListener
The ConnectionStateListener interface is provided when adding an outstation to the TCP server. It has a single method that informs your code when the outstation accepts a TCP connection.
The listener only fires a connected event when it receives an IP address matching the AddressFilter. If the outstation that is already connected and processing a connection receives
another matching connection, the listener will fire a disconnected event before firing a connected event.
Binding the server
Once you've added all the outstations associated with the server, you can then bind the server which will cause it to start accepting connections.
- Rust
- C
- C++
- Java
- C#
// dropping the ServerHandle shuts down the server and outstation(s)
let _server_handle = server.bind().await?;
err = dnp3_outstation_server_bind(server);
// check error
server.bind();
server.bind();
server.Bind();
Binding may fail if the underlying socket bind/listen calls fail, such as when another process is already bound to that port.
The Rust bind method spawns the server onto the Tokio runtime, so it must be called from within the runtime. Use bind_no_spawn if you want to spawn the returned future yourself.