/// <summary> /// Removes client from local repository. /// </summary> /// <param name="clientId"></param> /// <returns></returns> private TcpClientInfo RemoveClientFromRepository(string clientId) { TcpClientInfo client = null; _clientRepo.TryRemove(clientId, out client); return(client); }
/// <summary> /// Gets client from local repository /// </summary> /// <param name="clientId"></param> /// <returns></returns> private TcpClientInfo GetClientFromRepository(string clientId) { TcpClientInfo client = null; _clientRepo.TryGetValue(clientId, out client); return(client); }
/// <summary> /// Disconnects a client /// </summary> /// <param name="clientId"></param> /// <returns></returns> public bool DisconnectClient(string clientId) { TcpClientInfo client = RemoveClientFromRepository(clientId); client?.Dispose(); return(client != null); }
/// <summary> /// Reads data from stream /// </summary> /// <param name="client"></param> /// <param name="clientInfo"></param> /// <param name="ct"></param> protected async Task ReadData(TcpClientInfo client) { // get buffer size int bufferSize = _config.SocketBufferSize; // Buffer for reading data byte[] buffer = new byte[bufferSize]; // Get a stream object for reading and writing NetworkStream stream = client.Client.GetStream(); // Loop to receive all the data sent by the client. stream.ReadTimeout = 2000; int i = 0; while (true) { // read data from steram try { i = await stream.ReadAsync(buffer, 0, bufferSize); } catch (IOException) { break; } catch (ObjectDisposedException) { break; } catch (Exception) { break; } // No data (end of strem) if (i == 0) { break; } // received data var receivedMessages = client.DataProcessor.ProcessReceivedRawData(buffer, i); // message received if (receivedMessages != null && receivedMessages.Any()) { receivedMessages.ToList().ForEach((msg) => _ = DataReceived(msg, client.Info.Id)); } } // Close connection client.Dispose(); }
/// <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> /// Sends data to client /// </summary> /// <param name="clientId"></param> /// <param name="data"></param> /// <returns></returns> public async Task <bool> SendMessageToClient(string clientId, byte[] data) { TcpClientInfo client = GetClientFromRepository(clientId); if (client != null) { DataContainer message = new DataContainer { ClientId = clientId, Payload = data, Time = DateTime.Now }; return(await SendMessage(client, message)); } return(false); }
/// <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> /// Puts client to local repository. /// </summary> /// <param name="client"></param> private void PutClientToRepository(TcpClientInfo client) { _clientRepo.TryAdd(client.Info.Id, client); }
/// <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); }