private void RemoveRequestHandler(ModbusTcpRequestHandler handler) { lock (this.Lock) { this.RequestHandlerSet.Remove(handler); this.Logger.LogInformation($"{this.RequestHandlerSet.Count} {(this.RequestHandlerSet.Count == 1 ? "client is" : "clients are")} connected"); } }
private void AddRequestHandler(ModbusTcpRequestHandler handler) { lock (this.Lock) { _requestHandlerSet.Add(handler); _logger.LogInformation($"{_requestHandlerSet.Count} {(_requestHandlerSet.Count == 1 ? "client is" : "clients are")} connected"); } }
/// <summary> /// Starts the server. It will listen on the provided <paramref name="localEndpoint"/>. /// </summary> public void Start(IPEndPoint localEndpoint) { // "base..." is important! base.Stop(); base.Start(); this.RequestHandlerSet = new List <ModbusTcpRequestHandler>(); _tcpListener = new TcpListener(localEndpoint); _tcpListener.Start(); // accept clients asynchronously _task_accept_clients = Task.Run(async() => { ModbusTcpRequestHandler handler; TcpClient tcpClient; while (!this.CTS.IsCancellationRequested) { // There are no default timeouts (SendTimeout and ReceiveTimeout = 0), // use ConnectionTimeout instead. tcpClient = await _tcpListener.AcceptTcpClientAsync(); handler = new ModbusTcpRequestHandler(tcpClient, this); this.AddRequestHandler(handler); } }, this.CTS.Token); // remove clients asynchronously _task_remove_clients = Task.Run(async() => { while (!this.CTS.IsCancellationRequested) { lock (this.Lock) { // see remarks to "TcpClient.Connected" property // https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connected?redirectedfrom=MSDN&view=netframework-4.8#System_Net_Sockets_TcpClient_Connected foreach (var requestHandler in this.RequestHandlerSet.ToList()) { if (requestHandler.LastRequest.Elapsed > this.ConnectionTimeout) { this.Logger.LogInformation($"Connection {requestHandler.DisplayName} timed out."); this.RemoveRequestHandler(requestHandler); requestHandler.Dispose(); } } } await Task.Delay(TimeSpan.FromSeconds(1)); } }, this.CTS.Token); }
/// <summary> /// Starts the server. It will accept all TCP clients provided by the provided <see cref="ITcpClientProvider"/>. /// </summary> /// <param name="tcpClientProvider">The TCP client provider.</param> /// <param name="leaveOpen"><see langword="true"/> to leave the TCP client provider open after the <see cref="ModbusTcpServer"/> object is stopped or disposed; otherwise, <see langword="false"/>.</param> public void Start(ITcpClientProvider tcpClientProvider, bool leaveOpen = false) { _tcpClientProvider = tcpClientProvider; _leaveOpen = leaveOpen; base.StopProcessing(); base.StartProcessing(); this.RequestHandlers = new List <ModbusTcpRequestHandler>(); // accept clients asynchronously /* https://stackoverflow.com/questions/2782802/can-net-task-instances-go-out-of-scope-during-run */ Task.Run(async() => { while (!this.CTS.IsCancellationRequested) { // There are no default timeouts (SendTimeout and ReceiveTimeout = 0), // use ConnectionTimeout instead. var tcpClient = await _tcpClientProvider.AcceptTcpClientAsync(); var requestHandler = new ModbusTcpRequestHandler(tcpClient, this); lock (this.Lock) { if (this.MaxConnections > 0 && /* request handler is added later in 'else' block, so count needs to be increased by 1 */ this.RequestHandlers.Count + 1 > this.MaxConnections) { tcpClient.Close(); } else { this.RequestHandlers.Add(requestHandler); this.Logger.LogInformation($"{this.RequestHandlers.Count} {(this.RequestHandlers.Count == 1 ? "client is" : "clients are")} connected"); } } } }, this.CTS.Token); // remove clients asynchronously /* https://stackoverflow.com/questions/2782802/can-net-task-instances-go-out-of-scope-during-run */ Task.Run(async() => { while (!this.CTS.IsCancellationRequested) { lock (this.Lock) { // see remarks to "TcpClient.Connected" property // https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connected?redirectedfrom=MSDN&view=netframework-4.8#System_Net_Sockets_TcpClient_Connected foreach (var requestHandler in this.RequestHandlers.ToList()) { if (requestHandler.LastRequest.Elapsed > this.ConnectionTimeout) { try { this.Logger.LogInformation($"Connection {requestHandler.DisplayName} timed out."); lock (this.Lock) { // remove request handler this.RequestHandlers.Remove(requestHandler); this.Logger.LogInformation($"{this.RequestHandlers.Count} {(this.RequestHandlers.Count == 1 ? "client is" : "clients are")} connected"); } requestHandler.Dispose(); } catch { // ignore error } } } } await Task.Delay(TimeSpan.FromSeconds(1)); } }, this.CTS.Token); }
/// <summary> /// Starts the server. It will listen on the provided <paramref name="localEndpoint"/>. /// </summary> public void Start(IPEndPoint localEndpoint) { this.Stop(); _requestHandlerSet = new List <ModbusTcpRequestHandler>(); _tcpListener = new TcpListener(localEndpoint); _tcpListener.Start(); _cts = new CancellationTokenSource(); this.GetInputRegisterBuffer().Clear(); this.GetHoldingRegisterBuffer().Clear(); this.GetCoilBuffer().Clear(); this.GetDiscreteInputBuffer().Clear(); // accept clients asynchronously _task_accept_clients = Task.Run(async() => { ModbusTcpRequestHandler handler; TcpClient tcpClient; while (!_cts.IsCancellationRequested) { tcpClient = await _tcpListener.AcceptTcpClientAsync(); handler = new ModbusTcpRequestHandler(tcpClient, this); this.AddRequestHandler(handler); } }, _cts.Token); // remove clients asynchronously _task_remove_clients = Task.Run(async() => { while (!_cts.IsCancellationRequested) { lock (this.Lock) { // see remarks to "TcpClient.Connected" property // https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connected?redirectedfrom=MSDN&view=netframework-4.8#System_Net_Sockets_TcpClient_Connected foreach (var requestHandler in _requestHandlerSet.ToList()) { if (requestHandler.LastRequest.Elapsed > TimeSpan.FromMinutes(1)) { this.RemoveRequestHandler(requestHandler); requestHandler.Dispose(); } } } await Task.Delay(TimeSpan.FromSeconds(1)); } }, _cts.Token); if (!this.IsAsynchronous) { // only process requests when it is explicitly triggered _task_process_requests = Task.Run(() => { _manualResetEvent.Wait(_cts.Token); while (!_cts.IsCancellationRequested) { this.ProcessRequests(); _manualResetEvent.Reset(); _manualResetEvent.Wait(_cts.Token); } }, _cts.Token); } }