DiCE API nvidia_logo_transpbg.gif Up
Example for Networking modes
[Previous] [Next] [Up]

This example starts the DiCE API in different networking modes.

New Topics

  • Starting and configuring different networking modes

Detailed Description

General


This example just shows the basic configuration options to set up the different networking modes. Further configuration options related to networking are provided by the mi::neuraylib::INetwork_configuration interface. A simple implementation of the mi::neuraylib::IHost_callback interface is used to track network changes.

See also Networking Configuration for a general discussion about the advantages and disadvantages of the available networking modes.

No networking


This mode is the default, since it does not require any additional configuration. In this mode each instance of the DiCE API is separate. There are no attempts to connect to other instances. This mode was already used in the previous examples. It is part of this example program just for a matter of completeness.

UDP mode


The UDP mode is the simplest networking mode (apart from no networking at all). All it requires is an UDP multicast address and port number. All hosts with instances of the DiCE API than can be reached via this multicast address join a single cluster. The cluster can be restricted to certain set of hosts by using an optional discovery identifier. This option allows a fine-grained control over potential members of a particular cluster.

TCP mode


In TCP mode it is necessary to specify all hosts participating in the cluster in advance. Apart from your address and port, you have to specify the addresses and ports of all other hosts. Since this mode is not very flexible it is recommended to use TCP mode with discovery instead.

TCP mode with discovery


This mode is similar to TCP, but there is a discovery mechanism which eliminates the need to specify the addresses and ports of all other hosts. There are two variants of this mode: discovery via multicast or discovery via a client node. In the multicast variant you have to specify a common multicast address which is used by all hosts during the discovery phase to join the cluster. In the client variant you have to specify a common unicast address. The host with the given IP address acts as client during the discovery phase, all other hosts connect to this host to join the cluster. In both variants TCP is used as in the TCP mode without discovery after the host connected to the cluster. Similar to the UDP mode an optional discovery identifier can be used to restrict the cluster to a certain set of hosts.

Example Source

Source Code Location: examples/example_networking.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_networking.cpp
//
// Demonstrates usage of the different networking modes
//
// The example expects the following command line arguments:
//
// example_networking <mode> <multicast_address> <cluster_interface> <discovery_address>
// [<host1> <host2> ... <hostN>]
//
// mode "OFF", "UDP", "TCP", or ";TCP_WITH_DISCOVERY"
// multicast_address IPv4 or IPv6 address and port, or "."
// cluster_interface IPv4 or IPv6 address and port, or "."
// discovery_address IPv4 or IPv6 address and port, or "."
//
// The special value "." represents the "don't care" value for any address.
// If mode is "TCP", the remaining arguments are interpreted as hosts to configure.
//
// Examples:
//
// No networking
//
// @any host: ./example_networking OFF . . .
//
// UDP mode with three hosts
//
// @192.168.1.1: ./example_networking UDP 224.1.1.1:1111 . .
// @192.168.1.2: ./example_networking UDP 224.1.1.1:1111 . .
// @192.168.1.3: ./example_networking UDP 224.1.1.1:1111 . .
//
// TCP mode with three hosts
//
// @192.168.1.1: ./example_networking TCP . 192.168.1.1:1111 . 192.168.1.2:2222 192.168.1.3:3333
// @192.168.1.2: ./example_networking TCP . 192.168.1.2:2222 . 192.168.1.1:1111 192.168.1.3:3333
// @192.168.1.3: ./example_networking TCP . 192.168.1.3:3333 . 192.168.1.1:1111 192.168.1.2:2222
//
// TCP_WITH_DISCOVERY mode with three hosts (via multicast)
//
// @192.168.1.1: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.1:1111 224.1.1.1:4444
// @192.168.1.2: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.2:2222 224.1.1.1:4444
// @192.168.1.3: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.3:3333 224.1.1.1:4444
//
// TCP_WITH_DISCOVERY mode with three hosts (via a head node)
// Note that the client needs to be the only node running on its IP address.
//
// @192.168.1.1: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.1:1111 192.168.1.1:5555
// @192.168.1.2: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.2:2222 192.168.1.1:5555
// @192.168.1.3: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.3:3333 192.168.1.1:5555
#include <iostream>
#include <mi/dice.h>
// Include code shared by all examples.
#include "example_shared.h"
// This example implementation of the IHost_callback interface just prints a line
// for every event.
class Host_callback : public mi::base::Interface_implement<mi::neuraylib::IHost_callback>
{
public:
void connection_callback( mi::Uint32 host_id, bool flag)
{
if( flag) {
fprintf( stderr,
"The connection to the cluster was established. Own host id is %u.\n", host_id);
m_own_host_id = host_id;
}
else
fprintf( stderr, "The connection to the cluster was lost.\n");
}
void membership_callback( mi::Uint32 host_id, bool flag)
{
if( flag)
fprintf( stderr, "Host %u joined the cluster.\n", host_id);
else
fprintf( stderr, "Host %u left the cluster.\n", host_id);
}
void property_callback( mi::Uint32 host_id, const mi::neuraylib::IHost_properties* properties)
{
fprintf( stderr, "Host %u communicated its properties:\n", host_id);
mi::base::Handle<const mi::IString> value( properties->get_property( "application_name"));
if( value.is_valid_interface())
fprintf( stderr, " application_name: %s\n", value->get_c_str());
}
void synchronizer_callback( mi::Uint32 host_id)
{
fprintf( stderr, "The synchronizer is now host %u", host_id);
if( m_own_host_id == host_id)
fprintf( stderr, " (this host)");
fprintf( stderr, ".\n");
}
void database_status_callback( const char* status)
{
fprintf( stderr, "The database reports its status as \"%s\".\n", status);
}
private:
mi::Uint32 m_own_host_id;
};
void configuration(
int argc,
char* argv[])
{
// Register the callback handler
network_configuration->register_host_callback( host_callback);
// Set networking mode
const char* mode = argv[1];
if( strcmp( mode, ".") == 0) {
;
} else if( strcmp( mode, "OFF") == 0) {
check_success( network_configuration->set_mode(
} else if( strcmp( mode, "TCP") == 0) {
check_success( network_configuration->set_mode(
} else if( strcmp( mode, "UDP") == 0) {
check_success( network_configuration->set_mode(
} else if( strcmp( mode, ";TCP_WITH_DISCOVERY") == 0) {
check_success( network_configuration->set_mode(
} else {
check_success( false);
}
// Set the multicast address
if( strcmp( argv[2], ".") != 0)
check_success( network_configuration->set_multicast_address( argv[2]) == 0);
// Set the cluster interface
if( strcmp( argv[3], ".") != 0)
check_success( network_configuration->set_cluster_interface( argv[3]) == 0);
// Set the discovery address
if( strcmp( argv[4], ".") != 0)
check_success( network_configuration->set_discovery_address( argv[4]) == 0);
// Add configured hosts
for( int i = 5; i < argc; ++i)
check_success( network_configuration->add_configured_host( argv[i]) == 0);
// Set a host property
general_configuration->set_host_property( "application_name", "example_networking");
}
void print_configuration( mi::neuraylib::INeuray* neuray)
{
// Print networking mode
mi::neuraylib::INetwork_configuration::Mode mode = network_configuration->get_mode();
switch( mode) {
fprintf( stderr, "mode: OFF\n");
break;
fprintf( stderr, "mode: TCP\n");
break;
fprintf( stderr, "mode: UDP\n");
break;
fprintf( stderr, "mode: TCP_WITH_DISCOVERY\n");
break;
default:
fprintf( stderr, "mode: error\n");
break;
}
// Print the multicast address
mi::base::Handle<const mi::IString> string( network_configuration->get_multicast_address());
fprintf( stderr, "multicast address: %s\n", string->get_c_str());
// Print the cluster interface
string = network_configuration->get_cluster_interface();
fprintf( stderr, "cluster interface: %s\n", string->get_c_str());
// Print the discovery address
string = network_configuration->get_discovery_address();
fprintf( stderr, "discovery address: %s\n", string->get_c_str());
// Print the configured hosts
fprintf( stderr, "configured hosts: ");
for( mi::Uint32 i = 0; i < network_configuration->get_number_of_configured_hosts(); ++i) {
string = network_configuration->get_configured_host( i);
fprintf( stderr, "%s ", string->get_c_str());
}
fprintf( stderr, "\n");
}
int main( int argc, char* argv[])
{
// Check command line parameters
if( argc < 5) {
std::cerr << "Usage: example_networking <mode> <multicast_address> <cluster_interface>\\\n"
<< " <discovery_address> [<host1> <host2> ... <hostN>]" << std::endl;
keep_console_open();
return EXIT_FAILURE;
}
// Access the DiCE library
mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
check_success( neuray.is_valid_interface());
// Create callback handler
mi::base::Handle<mi::neuraylib::IHost_callback> host_callback( new Host_callback());
// Configure the DiCE library
configuration( neuray.get(), host_callback.get(), argc, argv);
// Print the configuration
print_configuration( neuray.get());
// Start the DiCE library
mi::Sint32 result = neuray->start();
check_start_success( result);
// Wait for other hosts to join/leave the cluster. The Host_callback objects prints
// messages of joining or leaving hosts.
sleep_seconds( 30);
// Shut down the DiCE library
check_success( neuray->shutdown() == 0);
// Unregister the callback handler again
network_configuration->unregister_host_callback( host_callback.get());
network_configuration = 0;
neuray = 0;
// Unload the DiCE library
check_success( unload());
keep_console_open();
return EXIT_SUCCESS;
}
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
Mixin class template for deriving interface implementations.
Definition: interface_implement.h:41
This interface is used to query and change the general configuration.
Definition: igeneral_configuration.h:25
Abstract interface to report cluster status changes.
Definition: ihost_callback.h:35
This interface contains information about a local or remote host.
Definition: ihost_properties.h:27
virtual const IString * get_property(const char *key) const =0
Generic access to properties.
This interface is used to query and change the networking configuration.
Definition: inetwork_configuration.h:33
Mode
Constants for the networking mode.
Definition: inetwork_configuration.h:42
@ MODE_UDP
Networking is switched to UDP mode with multicast.
Definition: inetwork_configuration.h:53
@ MODE_OFF
Networking is switched off.
Definition: inetwork_configuration.h:44
@ MODE_TCP_WITH_DISCOVERY
Networking is using TCP/IP connections between hosts.
Definition: inetwork_configuration.h:57
@ MODE_TCP
Networking is using TCP/IP connections between hosts.
Definition: inetwork_configuration.h:48
This is an object representing the DiCE library.
Definition: ineuray.h:44
virtual Sint32 shutdown(bool blocking=true)=0
Shuts down the library.
virtual base::IInterface * get_api_component(const base::Uuid &uuid) const =0
Returns an API component from the DiCE API.
virtual Sint32 start(bool blocking=true)=0
Starts the operation of the DiCE library.
DiCE API.
unsigned int Uint32
32-bit unsigned integer.
Definition: types.h:49
signed int Sint32
32-bit signed integer.
Definition: types.h:46
[Previous] [Next] [Up]