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() { return this.ToItemArray().OrderBy(item => item.PingElapsed).Select(item => item.Address).ToArray(); } /// /// Ping所有IP /// /// public Task PingAllAsync() { var items = this.ToItemArray(); if (items.Length == 0) { return Task.CompletedTask; } if (items.Length == 1) { return items[0].PingAsync(); } var tasks = items.Select(item => item.PingAsync()); return Task.WhenAll(tasks); } /// /// 转换为数组 /// /// private IPAddressItem[] ToItemArray() { lock (this.syncRoot) { return this.hashSet.ToArray(); } } /// /// IP地址项 /// [DebuggerDisplay("Address = {Address}, PingElapsed = {PingElapsed}")] private class IPAddressItem : IEquatable { /// /// 地址 /// 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() { 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; } } 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(); } } } }