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
}
}