예제 #1
0
        private async Task <bool> OpenTcpSocketAsync(ConnectionSettings cs, ILoadBalancer loadBalancer, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            var hostNames = loadBalancer.LoadBalance(cs.HostNames);

            foreach (var hostName in hostNames)
            {
                IPAddress[] ipAddresses;
                try
                {
#if NETSTANDARD1_3
// Dns.GetHostAddresses isn't available until netstandard 2.0: https://github.com/dotnet/corefx/pull/11950
                    ipAddresses = await Dns.GetHostAddressesAsync(hostName).ConfigureAwait(false);
#else
                    if (ioBehavior == IOBehavior.Asynchronous)
                    {
                        ipAddresses = await Dns.GetHostAddressesAsync(hostName).ConfigureAwait(false);
                    }
                    else
                    {
                        ipAddresses = Dns.GetHostAddresses(hostName);
                    }
#endif
                }
                catch (SocketException)
                {
                    // name couldn't be resolved
                    continue;
                }

                // need to try IP Addresses one at a time: https://github.com/dotnet/corefx/issues/5829
                foreach (var ipAddress in ipAddresses)
                {
                    TcpClient tcpClient = null;
                    try
                    {
                        tcpClient = new TcpClient(ipAddress.AddressFamily);

                        using (cancellationToken.Register(() => tcpClient?.Client?.Dispose()))
                        {
                            try
                            {
                                if (ioBehavior == IOBehavior.Asynchronous)
                                {
                                    await tcpClient.ConnectAsync(ipAddress, cs.Port).ConfigureAwait(false);
                                }
                                else
                                {
#if NETSTANDARD1_3
                                    await tcpClient.ConnectAsync(ipAddress, cs.Port).ConfigureAwait(false);
#else
                                    if (Utility.IsWindows())
                                    {
                                        tcpClient.Connect(ipAddress, cs.Port);
                                    }
                                    else
                                    {
                                        // non-windows platforms block on synchronous connect, use send/receive timeouts: https://github.com/dotnet/corefx/issues/20954
                                        var originalSendTimeout    = tcpClient.Client.SendTimeout;
                                        var originalReceiveTimeout = tcpClient.Client.ReceiveTimeout;
                                        tcpClient.Client.SendTimeout    = cs.ConnectionTimeoutMilliseconds;
                                        tcpClient.Client.ReceiveTimeout = cs.ConnectionTimeoutMilliseconds;
                                        tcpClient.Connect(ipAddress, cs.Port);
                                        tcpClient.Client.SendTimeout    = originalSendTimeout;
                                        tcpClient.Client.ReceiveTimeout = originalReceiveTimeout;
                                    }
#endif
                                }
                            }
                            catch (ObjectDisposedException ex) when(cancellationToken.IsCancellationRequested)
                            {
                                throw new MySqlException("Connect Timeout expired.", ex);
                            }
                        }
                    }
                    catch (SocketException)
                    {
                        tcpClient?.Client?.Dispose();
                        continue;
                    }

                    HostName        = hostName;
                    m_tcpClient     = tcpClient;
                    m_socket        = m_tcpClient.Client;
                    m_networkStream = m_tcpClient.GetStream();
                    m_socket.SetKeepAlive(cs.Keepalive);
                    lock (m_lock)
                        m_state = State.Connected;
                    return(true);
                }
            }
            return(false);
        }