Unlike Windows, the sockets API on Linux and OSX does not allow a single socket to attempt more than one connection. We had attempted to do this on Linux, but it did not work (see #16238).
Socket has multiple methods that depend on being able to try connections to multiple endpoints on a single socket:
public void Connect(IPAddress[] addresses, int port)
...attempts to connect to each of addresses, returning when one of them is successful.
public void Connect(string host, int port)
...does a DNS lookup, which may return multiple addresses, then attempts to connect to each of them until successful.
public void Connect(EndPoint remoteEP)
If this is passed a DnsEndPoint, then this behaves the same as Connect(string, int), trying all resolved addresses.
Additionally, we support async variants of all of these.
On Unix we currently "fake" this by creating multiple temporary sockets behind the scenes, trying to connect each of them to a different address. If one succeeds, we immediately disconnect it and connect the "real" socket to that address. This workaround has some possibly unacceptable implications:
-
Whichever endpoint we finally choose, we will end up connecting to it twice, once for the "probe" connection, to see if it will work, and again for the "real" connection. This will cause issues for servers that do not expect more than one connection, for load balancers that try to distribute connections, etc. It's also a lot of undesired network overhead.
-
Even though the first connection attempt succeeded, the second will not necessarily succeed. This is especially true in scenarios like DNS-based load balancing. So we have a functional issue here, where we may fail to connect the "real" socket in cases where we would have succeeded.
I do not think we should leave this as-is, as it will create too many unexpected strange behaviors in code that uses these, expecting them to behave the same way as they do on Windows. So I propose doing one of the following:
a) Remove the Connect overloads that take multiple endpoints, and the DnsEndpoint type, from the public contracts.
-- or --
b) Change these Connect overloads to throw PlatformNotSupportedException on Unix, Also, change Connect(EndPoint, int) to throw PlatformNotSupportedException if passed a DnsEndPoint.
In either case, we should provide sample code for how to code equivalent behavior using the remaining APIs.
@stephentoub, @pgavlin, @CIPop, @davidsh, @SidharthNabar, please provide feedback.
Unlike Windows, the sockets API on Linux and OSX does not allow a single socket to attempt more than one connection. We had attempted to do this on Linux, but it did not work (see #16238).
Sockethas multiple methods that depend on being able to try connections to multiple endpoints on a single socket:...attempts to connect to each of
addresses, returning when one of them is successful....does a DNS lookup, which may return multiple addresses, then attempts to connect to each of them until successful.
If this is passed a
DnsEndPoint, then this behaves the same asConnect(string, int), trying all resolved addresses.Additionally, we support async variants of all of these.
On Unix we currently "fake" this by creating multiple temporary sockets behind the scenes, trying to connect each of them to a different address. If one succeeds, we immediately disconnect it and connect the "real" socket to that address. This workaround has some possibly unacceptable implications:
Whichever endpoint we finally choose, we will end up connecting to it twice, once for the "probe" connection, to see if it will work, and again for the "real" connection. This will cause issues for servers that do not expect more than one connection, for load balancers that try to distribute connections, etc. It's also a lot of undesired network overhead.
Even though the first connection attempt succeeded, the second will not necessarily succeed. This is especially true in scenarios like DNS-based load balancing. So we have a functional issue here, where we may fail to connect the "real" socket in cases where we would have succeeded.
I do not think we should leave this as-is, as it will create too many unexpected strange behaviors in code that uses these, expecting them to behave the same way as they do on Windows. So I propose doing one of the following:
a) Remove the
Connectoverloads that take multiple endpoints, and theDnsEndpointtype, from the public contracts.-- or --
b) Change these Connect overloads to throw
PlatformNotSupportedExceptionon Unix, Also, changeConnect(EndPoint, int)to throwPlatformNotSupportedExceptionif passed aDnsEndPoint.In either case, we should provide sample code for how to code equivalent behavior using the remaining APIs.
@stephentoub, @pgavlin, @CIPop, @davidsh, @SidharthNabar, please provide feedback.