2
\$\begingroup\$

TCP/IP server which controls up to 500 clients. There's a list of added computers and the server gets this list, selects computers which are not already connected and ping them using host name.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;
using Timer = System.Threading.Timer;

namespace Server.Communications
{
    /// <summary>
    /// Checks statuses of computers (online/offline) which are not connected to server.
    /// </summary>
    [ServiceId(ServiceId.RemoteComputersService)]
    public class RemoteComputersService : PublicService, IDisposable
    {
        private Timer _timer;
        private bool _skipTimerElapse;

        public RemoteComputersService(ServerTools tools)
            : base(tools)
        { }

        /// <summary>
        /// Ping function to check status of EAM client before creating pipe to avoid stuck
        /// </summary>
        /// <param name="clientName">Domain or workgroup name of computer.</param>
        /// <param name="computerId">Computer id.</param>
        /// <returns>True if computer is online.</returns>
        private async Task<ComputerPingReply> IsMachineOnlineAsync(string clientName, long computerId)
        {
            try
            {
                var ping = new Ping();
                var pingReply = await ping.SendPingAsync(clientName, 500);

                return new ComputerPingReply(computerId, pingReply);
            }
            catch (Exception)
            {
                return new ComputerPingReply(computerId, null);
            }
        }

        private async Task PingAllComputers(IEnumerable<Computer> computers)
        {
            var pingConnectionStatus = computers
                .Select(computer => IsMachineOnlineAsync(computer.HostName, computer.ComputerId))
                .ToList();

            while (pingConnectionStatus.Count > 0)
            {
                //Wait for the first end task
                var task = await Task.WhenAny(pingConnectionStatus);

                pingConnectionStatus.Remove(task);

                var result = await task;

                //Do nothing if computer is already connected
                if (result.PingReply != null &&
                    SSLDaemonProviderService.IsComputerConnected(result.ComputerId)) continue;

                var connectionStatus = result.PingReply == null ||
                                       result.PingReply.Status != IPStatus.Success
                    ? ConnectionStatus.Offline
                    : ConnectionStatus.Online;
                ComputerInfoProviderService.UpdateConnectionStatus(connectionStatus, result.ComputerId);
            }
        }

        private async void CheckRemoteComputers()
        {
            if (_skipTimerElapse) return;

            _skipTimerElapse = true;
            try
            {
                // Computers which are not connected to server shall be checked only.
                var allComputers = ComputerInfoProviderService.GetComputers();
                var notConnectedComputers = allComputers
                    .Where(c => !SSLDaemonProviderService.IsComputerConnected(c.ComputerId))
                    .OrderBy(c => Guid.NewGuid()) //randomize list of computers
                    .ToArray();

                if (notConnectedComputers.Length == 0) return;
                Tools.LogDebug(Localization.RemoteComputersService.PingingOfRemoteComputersStarted, notConnectedComputers.Length);

                await PingAllComputers(notConnectedComputers);
            }
            catch (Exception ex)
            {
                Tools.LogException(ex);
            }
            finally
            {
                Tools.LogDebug(Localization.RemoteComputersService.PingingOfRemoteComputersFinished);
                _skipTimerElapse = false;
            }
        }

        protected override void OnStart()
        {
            _timer = new Timer(
                _ => CheckRemoteComputers(),
                null,
                TimeSpan.Zero, 
                TimeSpan.FromMinutes(10));
        }

        protected override void OnStop()
        {
            Dispose();
        }

        #region IDisposable

        private bool _disposed;

        private void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing)
            {
                _timer.Dispose();
            }

            _disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
        }

        #endregion
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ The description for this question is also very general. Please give us more details like what do you mean by in a solid way. How is it pinging the clients etc etc. \$\endgroup\$ – t3chb0t Jul 19 '18 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.