Networking modes
This topic introduces:
- The different networking modes:
- The program example_networking.cpp, which 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 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 Iray 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 a UDP multicast address and port number. All hosts with instances of the Iray API than can be reached via this multicast address join a single cluster. The cluster can be restricted to certain sets 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 master 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 master variant you have to specify a common unicast address. The host with the given IP address acts as master 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_networking.cpp
001 /****************************************************************************** 002 * © 1986, 2016 NVIDIA Corporation. All rights reserved. 003 *****************************************************************************/ 004 005 // examples/example_networking.cpp 006 // 007 // Demonstrates usage of the different networking modes 008 // 009 // The example expects the following command line arguments: 010 // 011 // example_networking <mode> <multicast_address> <cluster_interface> <discovery_address> 012 // [<host1> <host2> ... <hostN>] 013 // 014 // mode "OFF", "UDP", "TCP", or "TCP_WITH_DISCOVERY" 015 // multicast_address IPv4 or IPv6 address and port, or "." 016 // cluster_interface IPv4 or IPv6 address and port, or "." 017 // discovery_address IPv4 or IPv6 address and port, or "." 018 // 019 // The special value "." represents the "don't care" value for any address. 020 // If mode is "TCP", the remaining arguments are interpreted as hosts to configure. 021 // 022 // Examples: 023 // 024 // No networking 025 // 026 // @any host: ./example_networking OFF . . . 027 // 028 // UDP mode with three hosts 029 // 030 // @192.168.1.1: ./example_networking UDP 224.1.1.1:1111 . . 031 // @192.168.1.2: ./example_networking UDP 224.1.1.1:1111 . . 032 // @192.168.1.3: ./example_networking UDP 224.1.1.1:1111 . . 033 // 034 // TCP mode with three hosts 035 // 036 // @192.168.1.1: ./example_networking TCP . 192.168.1.1:1111 . 192.168.1.2:2222 192.168.1.3:3333 037 // @192.168.1.2: ./example_networking TCP . 192.168.1.2:2222 . 192.168.1.1:1111 192.168.1.3:3333 038 // @192.168.1.3: ./example_networking TCP . 192.168.1.3:3333 . 192.168.1.1:1111 192.168.1.2:2222 039 // 040 // TCP_WITH_DISCOVERY mode with three hosts (via multicast) 041 // 042 // @192.168.1.1: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.1:1111 224.1.1.1:4444 043 // @192.168.1.2: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.2:2222 224.1.1.1:4444 044 // @192.168.1.3: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.3:3333 224.1.1.1:4444 045 // 046 // TCP_WITH_DISCOVERY mode with three hosts (via a head node) 047 // Note that the client needs to be the only node running on its IP address. 048 // 049 // @192.168.1.1: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.1:1111 192.168.1.1:5555 050 // @192.168.1.2: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.2:2222 192.168.1.1:5555 051 // @192.168.1.3: ./example_networking TCP_WITH_DISCOVERY . 192.168.1.3:3333 192.168.1.1:5555 052 053 #include <iostream> 054 055 #include <mi/neuraylib.h> 056 057 // Include code shared by all examples. 058 #include "example_shared.h" 059 060 // This example implementation of the IHost_callback interface just prints a line 061 // for every event. 062 class Host_callback : public mi::base::Interface_implement<mi::neuraylib::IHost_callback> 063 { 064 public: 065 void connection_callback( mi::Uint32 host_id, bool flag) 066 { 067 if( flag) { 068 fprintf( stderr, 069 "The connection to the cluster was established. Own host id is %u.\n", host_id); 070 m_own_host_id = host_id; 071 } 072 else 073 fprintf( stderr, "The connection to the cluster was lost.\n"); 074 } 075 void membership_callback( mi::Uint32 host_id, bool flag) 076 { 077 if( flag) 078 fprintf( stderr, "Host %u joined the cluster.\n", host_id); 079 else 080 fprintf( stderr, "Host %u left the cluster.\n", host_id); 081 } 082 void property_callback( mi::Uint32 host_id, const mi::neuraylib::IHost_properties* properties) 083 { 084 fprintf( stderr, "Host %u communicated its properties:\n", host_id); 085 mi::base::Handle<const mi::IString> value( properties->get_property( "application_name")); 086 if( value.is_valid_interface()) 087 fprintf( stderr, " application_name: %s\n", value->get_c_str()); 088 } 089 void synchronizer_callback( mi::Uint32 host_id) 090 { 091 fprintf( stderr, "The synchronizer is now host %u", host_id); 092 if( m_own_host_id == host_id) 093 fprintf( stderr, " (this host)"); 094 fprintf( stderr, ".\n"); 095 } 096 void database_status_callback( const char* status) 097 { 098 fprintf( stderr, "The database reports its status as \"%s\".\n", status); 099 } 100 101 private: 102 mi::Uint32 m_own_host_id; 103 }; 104 105 void configuration( mi::base::Handle<mi::neuraylib::INeuray> neuray, 106 mi::base::Handle<mi::neuraylib::IHost_callback> host_callback, 107 int argc, 108 char* argv[]) 109 { 110 mi::base::Handle<mi::neuraylib::INetwork_configuration> network_configuration( 111 neuray->get_api_component<mi::neuraylib::INetwork_configuration>()); 112 113 // Register the callback handler 114 network_configuration->register_host_callback( host_callback.get()); 115 116 // Set networking mode 117 const char* mode = argv[1]; 118 if( strcmp( mode, ".") == 0) { 119 ; 120 } else if( strcmp( mode, "OFF") == 0) { 121 check_success( network_configuration->set_mode( 122 mi::neuraylib::INetwork_configuration::MODE_OFF) == 0); 123 } else if( strcmp( mode, "TCP") == 0) { 124 check_success( network_configuration->set_mode( 125 mi::neuraylib::INetwork_configuration::MODE_TCP) == 0); 126 } else if( strcmp( mode, "UDP") == 0) { 127 check_success( network_configuration->set_mode( 128 mi::neuraylib::INetwork_configuration::MODE_UDP) == 0); 129 } else if( strcmp( mode, "TCP_WITH_DISCOVERY") == 0) { 130 check_success( network_configuration->set_mode( 131 mi::neuraylib::INetwork_configuration::MODE_TCP_WITH_DISCOVERY) == 0); 132 } else { 133 check_success( false); 134 } 135 136 // Set the multicast address 137 if( strcmp( argv[2], ".") != 0) 138 check_success( network_configuration->set_multicast_address( argv[2]) == 0); 139 140 // Set the cluster interface 141 if( strcmp( argv[3], ".") != 0) 142 check_success( network_configuration->set_cluster_interface( argv[3]) == 0); 143 144 // Set the discovery address 145 if( strcmp( argv[4], ".") != 0) 146 check_success( network_configuration->set_discovery_address( argv[4]) == 0); 147 148 // Add configured hosts 149 for( int i = 5; i < argc; ++i) 150 check_success( network_configuration->add_configured_host( argv[i]) == 0); 151 152 // Set a host property 153 mi::base::Handle<mi::neuraylib::IGeneral_configuration> general_configuration( 154 neuray->get_api_component<mi::neuraylib::IGeneral_configuration>()); 155 general_configuration->set_host_property( "application_name", "example_networking"); 156 157 // Load the Iray Photoreal plugin. This is only relevant when the example is used in conjunction 158 // with the node manager example. 159 mi::base::Handle<mi::neuraylib::IPlugin_configuration> plugin_configuration( 160 neuray->get_api_component<mi::neuraylib::IPlugin_configuration>()); 161 #ifndef MI_PLATFORM_WINDOWS 162 check_success( plugin_configuration->load_plugin_library( "libiray.so") == 0); 163 #else 164 check_success( plugin_configuration->load_plugin_library( "libiray.dll") == 0); 165 #endif 166 } 167 168 void print_configuration( mi::base::Handle<mi::neuraylib::INeuray> neuray) 169 { 170 mi::base::Handle<mi::neuraylib::INetwork_configuration> network_configuration( 171 neuray->get_api_component<mi::neuraylib::INetwork_configuration>()); 172 173 // Print networking mode 174 mi::neuraylib::INetwork_configuration::Mode mode = network_configuration->get_mode(); 175 switch( mode) { 176 case mi::neuraylib::INetwork_configuration::MODE_OFF: 177 fprintf( stderr, "mode: OFF\n"); 178 break; 179 case mi::neuraylib::INetwork_configuration::MODE_TCP: 180 fprintf( stderr, "mode: TCP\n"); 181 break; 182 case mi::neuraylib::INetwork_configuration::MODE_UDP: 183 fprintf( stderr, "mode: UDP\n"); 184 break; 185 case mi::neuraylib::INetwork_configuration::MODE_TCP_WITH_DISCOVERY: 186 fprintf( stderr, "mode: TCP_WITH_DISCOVERY\n"); 187 break; 188 default: 189 fprintf( stderr, "mode: error\n"); 190 break; 191 } 192 193 // Print the multicast address 194 mi::base::Handle<const mi::IString> string( network_configuration->get_multicast_address()); 195 fprintf( stderr, "multicast address: %s\n", string->get_c_str()); 196 197 // Print the cluster interface 198 string = network_configuration->get_cluster_interface(); 199 fprintf( stderr, "cluster interface: %s\n", string->get_c_str()); 200 201 // Print the discovery address 202 string = network_configuration->get_discovery_address(); 203 fprintf( stderr, "discovery address: %s\n", string->get_c_str()); 204 205 // Print the configured hosts 206 fprintf( stderr, "configured hosts: "); 207 for( mi::Uint32 i = 0; i < network_configuration->get_number_of_configured_hosts(); ++i) { 208 string = network_configuration->get_configured_host( i); 209 fprintf( stderr, "%s ", string->get_c_str()); 210 } 211 fprintf( stderr, "\n"); 212 } 213 214 int main( int argc, char* argv[]) 215 { 216 // Collect command line parameters 217 if( argc < 5) { 218 std::cerr << "Usage: example_networking <mode> <multicast_address> \\" << std::endl; 219 std::cerr << " <cluster_interface> <discovery_address> \\" << std::endl; 220 std::cerr << " [<host1> <host2> ... <hostN>]" << std::endl; 221 keep_console_open(); 222 return EXIT_FAILURE; 223 } 224 225 // Access the neuray library 226 mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray()); 227 check_success( neuray.is_valid_interface()); 228 229 // Create callback handler 230 mi::base::Handle<mi::neuraylib::IHost_callback> host_callback( new Host_callback()); 231 232 // Configure the neuray library 233 configuration( neuray, host_callback, argc, argv); 234 235 // Print the configuration 236 print_configuration( neuray); 237 238 // Start the neuray library 239 mi::Sint32 result = neuray->start(); 240 check_start_success( result); 241 242 // Wait for other hosts to join/leave the cluster. The Host_callback objects prints 243 // messages of joining or leaving hosts. 244 sleep_seconds( 30); 245 246 // Shut down the neuray library 247 check_success( neuray->shutdown() == 0); 248 249 // Unregister the callback handler again 250 mi::base::Handle<mi::neuraylib::INetwork_configuration> network_configuration( 251 neuray->get_api_component<mi::neuraylib::INetwork_configuration>()); 252 network_configuration->unregister_host_callback( host_callback.get()); 253 network_configuration = 0; 254 neuray = 0; 255 256 // Unload the neuray library 257 check_success( unload()); 258 259 keep_console_open(); 260 return EXIT_SUCCESS; 261 }