using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Threading.Tasks; namespace FastGithub.DomainResolve { /// /// IPAddress集合 /// [DebuggerDisplay("Count = {Count}")] sealed class IPAddressCollection { private readonly object syncRoot = new(); private readonly HashSet hashSet = new(); /// /// 获取元素数量 /// public int Count => this.hashSet.Count; /// /// 添加元素 /// /// /// public bool Add(IPAddress address) { lock (this.syncRoot) { return this.hashSet.Add(new IPAddressItem(address)); } } /// /// 转后为数组 /// /// public IPAddress[] ToArray() { lock (this.syncRoot) { return this.hashSet.OrderBy(item => item.PingElapsed).Select(item => item.Address).ToArray(); } } /// /// Ping所有IP /// /// public async Task PingAllAsync() { foreach (var item in this.ToItemArray()) { await item.PingAsync(); } } /// /// 转换为数组 /// /// private IPAddressItem[] ToItemArray() { lock (this.syncRoot) { return this.hashSet.ToArray(); } } /// /// IP地址项 /// [DebuggerDisplay("Address = {Address}, PingElapsed = {PingElapsed}")] private class IPAddressItem : IEquatable { /// /// Ping的时间点 /// private int? pingTicks; /// /// 地址 /// public IPAddress Address { get; } /// /// Ping耗时 /// public TimeSpan PingElapsed { get; private set; } = TimeSpan.MaxValue; /// /// IP地址项 /// /// public IPAddressItem(IPAddress address) { this.Address = address; } /// /// 发起ping请求 /// /// public async Task PingAsync() { if (this.NeedToPing() == false) { return; } try { using var ping = new Ping(); var reply = await ping.SendPingAsync(this.Address); this.PingElapsed = reply.Status == IPStatus.Success ? TimeSpan.FromMilliseconds(reply.RoundtripTime) : TimeSpan.MaxValue; } catch (Exception) { this.PingElapsed = TimeSpan.MaxValue; } finally { this.pingTicks = Environment.TickCount; } } /// /// 是否需要ping /// 5分钟内只ping一次 /// /// private bool NeedToPing() { var ticks = this.pingTicks; if (ticks == null) { return true; } var pingTimeSpan = TimeSpan.FromMilliseconds(Environment.TickCount - ticks.Value); return pingTimeSpan > TimeSpan.FromMinutes(5d); } public bool Equals(IPAddressItem? other) { return other != null && other.Address.Equals(this.Address); } public override bool Equals(object? obj) { return obj is IPAddressItem other && this.Equals(other); } public override int GetHashCode() { return this.Address.GetHashCode(); } } } }