Beispiel #1
0
 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");
     }
 }
Beispiel #3
0
        /// <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);
            }
        }