private async void WriterLoop(TcpClient client) { try { while (true) { byte[] msg; lock (_lock) { if (_client != client) { return; } msg = _messageQueue.Peek(); } await TcpTransport.SendFramed(client.GetStream(), msg).ConfigureAwait(false); lock (_lock) { if (_messageQueue.Peek() == msg) { _messageQueue.Dequeue(); } if (_client != client) { return; } if (_messageQueue.Count == 0) { _logger.LogDebug("Message queue for {TargetEndPoint} empty, switching to state {ClientState}.", TargetEndPoint, State.Connected); _state = State.Connected; // a bit of paranoia: if (_keepAliveTimer != null) { _keepAliveTimer.Dispose(); } _keepAliveTimer = new Timer(_ => SendKeepAlive(client), null, Transport.KeepAliveInterval, Transport.KeepAliveInterval); return; } } } } catch (Exception ex) { OnCloseOrError(client, ex); } }
private async void SendKeepAlive(TcpClient client) { try { lock (_lock) { if (_client != client || _state != State.Connected) { return; } // to block any concurrent attempts to send, since only one thread may send over a TcpClient at one time. _state = State.Sending; } _logger.LogDebug("Sending keep-alive to {TargetEndPoint}", TargetEndPoint); await TcpTransport.SendFramed(client.GetStream(), new byte[0]).ConfigureAwait(false); lock (_lock) { if (_client != client || _state != State.Sending) { return; } if (_messageQueue.Count > 0) { StartSending(); } else { _state = State.Connected; } } } catch (Exception ex) { OnCloseOrError(client, ex); } }