private void GetChannelAndSubscription(string localIp, int streamId, out string clientChannel, out Subscription subscription) { // Finding port for the first time is slow and in tests with // parallel connections many clients have different ports. // Simple lock is needed. lock (_connectionsLock) { while (true) { if (_clientPort == 0) { var clientPort = 0; while (true) { try { clientPort = UdpUtils.GetRandomUnusedPort(); clientChannel = Utils.RemoteChannel(localIp, clientPort); subscription = _client.AddSubscription(clientChannel, streamId); break; } catch (RegistrationException ex) { // if port was already reused by someone _log.Warn($"Could not subscribe on new port {clientPort}", ex); } } _clientPort = clientPort; return; } try { clientChannel = Utils.RemoteChannel(localIp, _clientPort); subscription = _client.AddSubscription(clientChannel, streamId); return; } catch (RegistrationException ex) { _log.Warn($"Could not subscribe on existing port {_clientPort}", ex); _clientPort = 0; } } } }
public int Connect(string serverHost, int serverPort, Action onConnectedDelegate, Action onDisconnectedDelegate, AeronClientMessageReceivedHandler onMessageReceived, int connectionResponseTimeoutMs) { if (serverHost == null) { throw new ArgumentNullException(nameof(serverHost)); } if (_isTerminatedUnexpectedly) { return(-1); } string serverHostIp; if (serverHost.Equals("localhost", StringComparison.OrdinalIgnoreCase) || serverHost.Equals("127.0.0.1", StringComparison.OrdinalIgnoreCase)) { // TODO IPC channel for local communication serverHostIp = "127.0.0.1"; } else { var ipv4 = Dns.GetHostEntry(serverHost).AddressList .FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork) ?? throw new ArgumentException($"Cannot resolve serverHost ip for {serverHost}"); serverHostIp = ipv4.ToString(); } var serverChannel = Utils.RemoteChannel(serverHostIp, serverPort); var publication = _client.AddExclusivePublication(serverChannel, AeronServer.ServerStreamId); var localIp = UdpUtils.GetLocalIPAddress(serverHostIp, serverPort); var streamId = MachineCounters.Instance.GetNewClientStreamId(); GetChannelAndSubscription(localIp, streamId, out var clientChannel, out var subscription); var session = new AeronClientSession(this, serverChannel, publication, subscription, onConnectedDelegate, onDisconnectedDelegate, onMessageReceived); var connectionId = AddSession(session); _log.Info($"Connecting: {session}"); var handshakeRequest = new AeronHandshakeRequest { Channel = clientChannel, StreamId = streamId }; if (!session.SendHandshake(handshakeRequest, connectionResponseTimeoutMs)) { RemoveSession(session); session.Dispose(); return(-1); } return(connectionId); }