Connection Establishment
7 min read
7 min read
7 min read
7 min read
7 min read
7 min read
7 min read
7 min read
7 min read
Ice establishes connections on demand. When an invocation on a proxy needs a connection, Ice reuses an existing connection if it can, and otherwise establishes a new connection to one of the proxy's endpoints.
Connection Reuse and Caching
Ice reuses connections at two levels:
- By default, a proxy caches the connection it obtains and uses it for its subsequent invocations.
- The communicator keeps the connections it establishes, and other proxies of this communicator share them.
When a proxy with connection caching enabled needs a connection, Ice prefers an endpoint that already has a connection. It reuses an existing connection that meets the following conditions, and establishes a new connection only when no existing connection does:
- The connection's remote endpoint matches one of the proxy's endpoints.
- The connection was established for the proxy's connection ID.
You disable connection caching with the ice_connectionCached proxy methodproxy methodproxy methodproxy methodproxy methodproxy methodproxy methodproxy method or the name.ConnectionCached property. Ice then selects an endpoint for each invocation on this proxy, in the order set by the endpoint selection policy and whether or not the endpoint already has a connection, and reuses an existing connection to this endpoint if there is one. With the default Random policy, disabling connection caching spreads a proxy's invocations across its endpoints.
The communicator manages the lifetime of its connections independently of the proxies that use them. Connections are long-lived: a healthy connection with regular activity stays open until the communicator is destroyed. The communicator closes a connection after a period of inactivity, 300 seconds by default, aborts a connection when a read or write fails or when the idle check fails, and closes all its connections when it is destroyed. When the connection a proxy caches closes, the proxy obtains a connection again for its next invocation.
Endpoint Selection
When a proxy needs a connection, Ice starts from the proxy's endpoints, or from the endpoints its locator returns for an indirect proxy, and produces the list of endpoints it can connect to as follows:
- It removes the endpoints of unknown transports.
- It removes the endpoints that do not suit the proxy's invocation mode: datagram endpoints for twoway, oneway and batch oneway proxies, and non-datagram endpoints for datagram and batch datagram proxies. If no endpoint remains, the invocation fails with
NoEndpointException. For example, a twoway proxy whose only endpoint is a UDP endpoint has no endpoint left. - It orders the endpoints according to the endpoint selection policy.
Random, the default, shuffles the endpoints;Orderedkeeps their order. - It resolves host names into IP addresses. When a host name resolves to several addresses, the list holds them in the order the DNS resolver returns them, with IPv4 addresses ahead of IPv6 addresses unless Ice.PreferIPv6Address is set. On iOS, the list holds the host names of TCP and SSL endpoints, not their addresses: the system resolves them when Ice connects.The list holds the host names, not their addresses: the JavaScript runtime resolves them when Ice connects.
You set the endpoint selection policy with the Ice.Default.EndpointSelection property, the name.EndpointSelection proxy property, or the ice_endpointSelection proxy methodproxy methodproxy methodproxy methodproxy methodproxy methodproxy methodproxy method.
Establishing the Connection
With connection caching enabled, Ice first reuses an existing connection to any endpoint in the list, so the connection it reuses is not necessarily to the first endpoint, even with the Ordered policy. When no existing connection qualifies, or when connection caching is disabled, Ice attempts to connect to each endpoint, and to each address of an endpoint, in order, until an attempt succeeds.
Connection IDs
Each proxy has a connection ID, an empty string by default, and Ice reuses a connection for a proxy only if the connection was established for the same connection ID. The ice_connectionId proxy methodproxy methodproxy methodproxy methodproxy methodproxy methodproxy methodproxy method returns a new proxy with the given connection ID. Proxies with the same connection ID form a group that shares connections, and Ice establishes a new connection for a group that has none to a suitable endpoint.
The following example establishes three connections:
SomePrx prx{communicator, "ident:tcp -p 10000"};auto g1 = prx.ice_connectionId("group1");auto g2 = prx.ice_connectionId("group2");prx.ice_ping(); // Opens a new connectiong1.ice_ping(); // Opens a new connectiong2.ice_ping(); // Opens a new connectionauto i1 = g1.ice_facet<AdminPrx>("admin");i1.ice_ping(); // Reuses g1's connectionauto i2 = prx.ice_connectionId("group2").ice_facet<AdminPrx>("admin");i2.ice_ping(); // Reuses g2's connectionvar prx = SomePrxHelper.createProxy(communicator, "ident:tcp -p 10000");var g1 = prx.ice_connectionId("group1");var g2 = prx.ice_connectionId("group2");await prx.ice_pingAsync(); // Opens a new connectionawait g1.ice_pingAsync(); // Opens a new connectionawait g2.ice_pingAsync(); // Opens a new connectionvar i1 = AdminPrxHelper.uncheckedCast(g1.ice_facet("admin"));await i1.ice_pingAsync(); // Reuses g1's connectionvar i2 = AdminPrxHelper.uncheckedCast( prx.ice_connectionId("group2").ice_facet("admin"));await i2.ice_pingAsync(); // Reuses g2's connectionvar prx = SomePrx.createProxy(communicator, "ident:tcp -p 10000");var g1 = prx.ice_connectionId("group1");var g2 = prx.ice_connectionId("group2");prx.ice_ping(); // Opens a new connectiong1.ice_ping(); // Opens a new connectiong2.ice_ping(); // Opens a new connectionvar i1 = AdminPrx.uncheckedCast(g1.ice_facet("admin"));i1.ice_ping(); // Reuses g1's connectionvar i2 = AdminPrx.uncheckedCast(prx.ice_connectionId("group2").ice_facet("admin"));i2.ice_ping(); // Reuses g2's connectionconst prx = new SomePrx(communicator, "ident:tcp -p 10000");const g1 = prx.ice_connectionId("group1");const g2 = prx.ice_connectionId("group2");await prx.ice_ping(); // Opens a new connectionawait g1.ice_ping(); // Opens a new connectionawait g2.ice_ping(); // Opens a new connectionconst i1 = AdminPrx.uncheckedCast(g1.ice_facet("admin"));await i1.ice_ping(); // Reuses g1's connectionconst i2 = AdminPrx.uncheckedCast( prx.ice_connectionId("group2").ice_facet("admin"));await i2.ice_ping(); // Reuses g2's connectionprx = SomePrx(communicator, 'ident:tcp -p 10000');g1 = prx.ice_connectionId('group1');g2 = prx.ice_connectionId('group2');prx.ice_ping(); % Opens a new connectiong1.ice_ping(); % Opens a new connectiong2.ice_ping(); % Opens a new connectioni1 = AdminPrx.uncheckedCast(g1.ice_facet('admin'));i1.ice_ping(); % Reuses g1's connectioni2 = AdminPrx.uncheckedCast(prx.ice_connectionId("group2").ice_facet("admin"));i2.ice_ping(); % Reuses g2's connection$prx = SomePrxHelper::createProxy($communicator, "ident:tcp -p 10000");$g1 = $prx->ice_connectionId("group1");$g2 = $prx->ice_connectionId("group2");$prx->ice_ping(); // Opens a new connection$g1->ice_ping(); // Opens a new connection$g2->ice_ping(); // Opens a new connection$i1 = AdminPrxHelper::uncheckedCast($g1->ice_facet("admin"));$i1->ice_ping(); // Reuses g1's connection$i2 = AdminPrxHelper::uncheckedCast( $prx->ice_connectionId("group2")->ice_facet("admin"));$i2->ice_ping(); // Reuses g2's connectionprx = SomePrx(communicator, "ident:tcp -p 10000")g1 = prx.ice_connectionId("group1")g2 = prx.ice_connectionId("group2")await prx.ice_pingAsync() # Opens a new connectionawait g1.ice_pingAsync() # Opens a new connectionawait g2.ice_pingAsync() # Opens a new connectioni1 = AdminPrx.uncheckedCast(g1.ice_facet("admin"))await i1.ice_pingAsync() # Reuses g1's connectioni2 = AdminPrx.uncheckedCast( prx.ice_connectionId("group2").ice_facet("admin"))await i2.ice_pingAsync() # Reuses g2's connectionprx = SomePrx.new(communicator, "ident:tcp -p 10000")g1 = prx.ice_connectionId("group1")g2 = prx.ice_connectionId("group2")prx.ice_ping() # Opens a new connectiong1.ice_ping() # Opens a new connectiong2.ice_ping() # Opens a new connectioni1 = AdminPrx::uncheckedCast(g1.ice_facet("admin"))i1.ice_ping() # Reuses g1's connectioni2 = AdminPrx::uncheckedCast( prx.ice_connectionId("group2").ice_facet("admin"))i2.ice_ping() # Reuses g2's connectionlet prx = try makeProxy( communicator: communicator, proxyString: "ident:tcp -p 10000", type: SomePrx.self)let g1 = prx.ice_connectionId("group1")let g2 = prx.ice_connectionId("group2")try await prx.ice_ping() // Opens a new connectiontry await g1.ice_ping() // Opens a new connectiontry await g2.ice_ping() // Opens a new connectionlet i1 = uncheckedCast(prx: g1.ice_facet("admin"), type: AdminPrx.self)try await i1.ice_ping() // Reuses g1's connectionlet i2 = uncheckedCast( prx: prx.ice_connectionId("group2").ice_facet("admin"), type: AdminPrx.self)try await i2.ice_ping() // Reuses g2's connectionprx, g1 and g2 each establish a connection because their connection IDs differ. i1 inherits its connection ID from g1 and shares the group1 connection; i2 is configured with group2 and shares the connection of g2.
Failed Connection Attempts
When a connection attempt fails, Ice tries the next address or endpoint, until it establishes a connection or has tried them all.
When every attempt fails, the invocation fails. An automatic retry of the invocation goes through connection establishment again.
Connection Establishment Timeout
A connection attempt fails with ConnectTimeoutException when it does not complete within the time set by Ice.Connection.Client.ConnectTimeout, 10 seconds by default.
Source Address for New Connections
Ice binds an outgoing connection to the source address of the endpoint it connects to. You set this address with the --sourceAddress endpoint option, and Ice gives the address set by Ice.Default.SourceAddress to the endpoints it parses without this option, such as those of a stringified proxy. An endpoint that Ice unmarshals, such as an endpoint returned by a locator, has no source address, and the operating system then selects the source address. Both settings take a numeric IP address. On iOS, Ice does not bind TCP and SSL connections to a source address.
In Ice for JavaScript, this applies to TCP connections in Node.js. WebSocket connections use the source address selected by the operating system.