/// <summary> /// Message received handler /// </summary> /// <param name="msg"></param> /// <param name="clientId"></param> private async Task DataReceived(byte[] msg, string clientId) { // create message model DataContainer model = new DataContainer { ClientId = clientId, Payload = msg, Time = DateTime.Now }; // trigger event _ = TaskUtil.RunAction(() => MsgReceivedAction?.Invoke(model), _logger); await Task.FromResult(true); }
/// <summary> /// Tcp server start task /// </summary> /// <param name="cts"></param> /// <returns></returns> public async Task <bool> ServerStart() { // already started if (_server != null) { _logger.LogInformation("Server already started."); return(false); } // clar clients repository _clientRepo.Clear(); // Init TCP listener var server = _config.IpAddress == null?TcpListener.Create(_config.Port) : new TcpListener(IPAddress.Parse(_config.IpAddress), _config.Port); // start server bool status = false; try { // Start listening for client requests. server.Start(); // set started status = true; } catch (Exception e) { _logger.LogError("Server failed to start on port {port}. Exception: {exception}", _config.Port, e.Message); } // set server Interlocked.Exchange(ref _server, server); // raise status event if (status) { _ = TaskUtil.RunAction(() => ServerStartedAction?.Invoke(_config), _logger); } else { _ = TaskUtil.RunAction(() => ServerStartFailureAction?.Invoke(_config), _logger); } // wait for clients (keep it run in background) if (status) { _ = WaitForClientsLoop(); } // finished return(await Task.FromResult(status)); }
/// <summary> /// Send message /// </summary> /// <param name="client"></param> /// <param name="message"></param> /// <returns></returns> protected async Task <bool> SendMessage(TcpClientInfo client, DataContainer message) { // decorate message to be sent over network byte[] msg = client.DataProcessor.FilterSendData(message.Payload); // sent message bool status = await SendData(client.Client, msg); // raise sent if (status) { _ = TaskUtil.RunAction(() => MsgSentAction?.Invoke(message), _logger); } return(status); }
/// <summary> /// Connect to server /// </summary> /// <param name="ct"></param> /// <returns></returns> public async Task <bool> Connect() { // create client or return if (_client != null) { return(true); } // init model info var client = new TcpClientInfo { Info = new ClientInfo() { Time = DateTime.Now, Port = _config.Port, IpAddress = _config.IpAddress, Id = Guid.NewGuid().ToString() }, Client = new TcpClient(), DataProcessor = _createDataProcessorFunc() }; // connect try { await client.Client.ConnectAsync(_config.IpAddress, _config.Port); } catch (Exception e) { _logger.LogError("Connection failed with error: {message}.", e.Message); // client connected failed _ = TaskUtil.RunAction(() => ClientConnectionFailureAction?.Invoke(client.Info), _logger); // return false return(false); } // set client Interlocked.Exchange(ref _client, client); // handle client _ = HandleClient(); // return success return(true); }
/// <summary> /// Handles a connected client /// </summary> /// <param name="client"></param> /// <param name="clientInfo"></param> private async Task HandleClient(TcpClientInfo client) { // trigger connected event _ = TaskUtil.RunAction(() => ClientConnectedAction?.Invoke(client.Info), _logger); // add client to repository PutClientToRepository(client); // continuously reads data (stops here until cancelled await ReadData(client); // remove client from repository RemoveClientFromRepository(client.Info.Id); // raise clinet disconnected _ = TaskUtil.RunAction(() => ClientDisconnectedAction?.Invoke(client.Info), _logger); }
/// <summary> /// Handles a connected client /// </summary> /// <param name="client"></param> /// <param name="ct"></param> private async Task HandleClient() { // client connected _ = TaskUtil.RunAction(() => ClientConnectedAction?.Invoke(_client.Info), _logger); // continuously reads data await ReadData(_client); // remove client from repository var client = Interlocked.Exchange(ref _client, null); _client?.Client.GetStream().Close(); _client?.Client?.Close(); _client = null; // trigger diconnected event _ = TaskUtil.RunAction(() => ClientDisconnectedAction?.Invoke(client?.Info), _logger); }
/// <summary> /// Wait for clients loop /// </summary> /// <returns></returns> private async Task WaitForClientsLoop() { try { // Enter the listening loop. while (true) { // Wait for client to connect. TcpClient client = await _server.AcceptTcpClientAsync(); // set client info TcpClientInfo clientModel = new TcpClientInfo { Info = new ClientInfo { Time = DateTime.Now, Port = _config.Port, IpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString(), Id = Guid.NewGuid().ToString() }, Client = client, DataProcessor = _createDataProcessorFunc(), }; // Handle client in background _ = HandleClient(clientModel); } } // socket errro catch (SocketException) { _logger.LogWarning("Server stopped. SocketException exception occured."); } // Listener was stopped. catch (ObjectDisposedException) { _logger.LogWarning("Server stopped. ObjectDisposedException exception occured."); } catch (InvalidOperationException) { _logger.LogWarning("Invalid operation exception."); } finally { // stop server try { TcpListener tcpListener = null; var srv = Interlocked.Exchange(ref _server, tcpListener); srv?.Stop(); } catch (SocketException) { } // disconnect client var clients = _clientRepo.Values.ToList(); _clientRepo.Clear(); clients.ForEach(c => { try { c.Dispose(); } catch (Exception) { } }); // log stop _logger.LogInformation("Server stopped."); } // server stopped _ = TaskUtil.RunAction(() => ServerStoppedAction?.Invoke(_config), _logger); }