From dd36207241543046f4ee2e5d1a0b5c2d9c04132f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E4=B9=9D?= <366193849@qq.com> Date: Fri, 19 Nov 2021 19:45:49 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B4=AF=E7=A7=AF=E5=8F=AF=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E7=9A=84IP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.DomainResolve/DomainResolver.cs | 65 +++++++------- FastGithub.DomainResolve/IPAddressElapsed.cs | 71 ++++++++++++---- .../IPAddressElapsedCollection.cs | 85 ------------------- 3 files changed, 88 insertions(+), 133 deletions(-) delete mode 100644 FastGithub.DomainResolve/IPAddressElapsedCollection.cs diff --git a/FastGithub.DomainResolve/DomainResolver.cs b/FastGithub.DomainResolve/DomainResolver.cs index 4a45025..af9d813 100644 --- a/FastGithub.DomainResolve/DomainResolver.cs +++ b/FastGithub.DomainResolve/DomainResolver.cs @@ -19,7 +19,7 @@ namespace FastGithub.DomainResolve private readonly DnsClient dnsClient; private readonly DomainPersistence persistence; private readonly ILogger logger; - private readonly ConcurrentDictionary dnsEndPointAddressElapseds = new(); + private readonly ConcurrentDictionary dnsEndPointAddressElapseds = new(); /// /// 域名解析器 @@ -38,7 +38,7 @@ namespace FastGithub.DomainResolve foreach (var endPoint in persistence.ReadDnsEndPoints()) { - this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty); + this.dnsEndPointAddressElapseds.TryAdd(endPoint, Array.Empty()); } } @@ -66,7 +66,7 @@ namespace FastGithub.DomainResolve /// public async IAsyncEnumerable ResolveAllAsync(DnsEndPoint endPoint, [EnumeratorCancellation] CancellationToken cancellationToken) { - if (this.dnsEndPointAddressElapseds.TryGetValue(endPoint, out var addressElapseds) && addressElapseds.IsEmpty == false) + if (this.dnsEndPointAddressElapseds.TryGetValue(endPoint, out var addressElapseds) && addressElapseds.Length > 0) { foreach (var addressElapsed in addressElapseds) { @@ -75,7 +75,7 @@ namespace FastGithub.DomainResolve } else { - if (this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty)) + if (this.dnsEndPointAddressElapseds.TryAdd(endPoint, Array.Empty())) { await this.persistence.WriteDnsEndPointsAsync(this.dnsEndPointAddressElapseds.Keys, cancellationToken); } @@ -96,36 +96,37 @@ namespace FastGithub.DomainResolve { foreach (var keyValue in this.dnsEndPointAddressElapseds) { - if (keyValue.Value.IsEmpty || keyValue.Value.IsExpired) + var dnsEndPoint = keyValue.Key; + var hashSet = new HashSet(); + + foreach (var item in keyValue.Value) { - var dnsEndPoint = keyValue.Key; - var addresses = new HashSet(); - foreach (var item in keyValue.Value) - { - addresses.Add(item.Adddress); - } - await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint, fastSort: false, cancellationToken)) - { - addresses.Add(adddress); - } - - var addressElapseds = IPAddressElapsedCollection.Empty; - if (addresses.Count == 1) - { - var addressElapsed = new IPAddressElapsed(addresses.First(), TimeSpan.Zero); - addressElapseds = new IPAddressElapsedCollection(addressElapsed); - } - else if (addresses.Count > 1) - { - var parseTasks = addresses.Select(address => IPAddressElapsed.ParseAsync(address, dnsEndPoint.Port, cancellationToken)); - var parseValues = await Task.WhenAll(parseTasks); - var connectedValues = parseValues.Where(item => item.Elapsed < TimeSpan.MaxValue); - addressElapseds = new IPAddressElapsedCollection(connectedValues); - } - - this.dnsEndPointAddressElapseds[dnsEndPoint] = addressElapseds; - this.logger.LogInformation($"{dnsEndPoint.Host}->{addressElapseds}"); + hashSet.Add(item); } + + await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint, fastSort: false, cancellationToken)) + { + hashSet.Add(new IPAddressElapsed(adddress, dnsEndPoint.Port)); + } + + var updateTasks = hashSet + .Where(item => item.CanUpdateElapsed()) + .Select(item => item.UpdateElapsedAsync(cancellationToken)); + + await Task.WhenAll(updateTasks); + + var addressElapseds = hashSet + .Where(item => item.Elapsed < TimeSpan.MaxValue) + .OrderBy(item => item.Elapsed) + .ToArray(); + + if (keyValue.Value.SequenceEqual(addressElapseds) == false) + { + var addressArray = string.Join(", ", addressElapseds.Select(item => item.ToString())); + this.logger.LogInformation($"{dnsEndPoint.Host}->[{addressArray}]"); + } + + this.dnsEndPointAddressElapseds[dnsEndPoint] = addressElapseds; } } } diff --git a/FastGithub.DomainResolve/IPAddressElapsed.cs b/FastGithub.DomainResolve/IPAddressElapsed.cs index 4d9cda8..f009047 100644 --- a/FastGithub.DomainResolve/IPAddressElapsed.cs +++ b/FastGithub.DomainResolve/IPAddressElapsed.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Sockets; using System.Threading; @@ -8,61 +9,99 @@ using System.Threading.Tasks; namespace FastGithub.DomainResolve { /// - /// IP延时 + /// IP延时记录 + /// 5分钟有效期 + /// 5秒连接超时 /// [DebuggerDisplay("Adddress={Adddress} Elapsed={Elapsed}")] - struct IPAddressElapsed + sealed class IPAddressElapsed : IEquatable { - private static readonly TimeSpan maxConnectTimeout = TimeSpan.FromSeconds(5d); + private static readonly long maxLifeTime = 5 * 60 * 1000; + private static readonly TimeSpan connectTimeout = TimeSpan.FromSeconds(5d); + + private long lastTestTickCount = 0L; /// /// 获取IP地址 /// public IPAddress Adddress { get; } + /// + /// 获取端口 + /// + public int Port { get; } + /// /// 获取延时 /// - public TimeSpan Elapsed { get; } + public TimeSpan Elapsed { get; private set; } = TimeSpan.MaxValue; /// /// IP延时 /// /// - /// - public IPAddressElapsed(IPAddress adddress, TimeSpan elapsed) + /// + public IPAddressElapsed(IPAddress adddress, int port) { this.Adddress = adddress; - this.Elapsed = elapsed; + this.Port = port; } /// - /// 获取连接耗时 + /// 是否可以更新延时 /// - /// - /// + /// + public bool CanUpdateElapsed() + { + return Environment.TickCount64 - this.lastTestTickCount > maxLifeTime; + } + + /// + /// 更新连接耗时 + /// /// /// - public static async Task ParseAsync(IPAddress address, int port, CancellationToken cancellationToken) + public async Task UpdateElapsedAsync(CancellationToken cancellationToken) { var stopWatch = Stopwatch.StartNew(); try { - using var timeoutTokenSource = new CancellationTokenSource(maxConnectTimeout); + using var timeoutTokenSource = new CancellationTokenSource(connectTimeout); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); - using var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - await socket.ConnectAsync(address, port, linkedTokenSource.Token); - return new IPAddressElapsed(address, stopWatch.Elapsed); + using var socket = new Socket(this.Adddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + await socket.ConnectAsync(this.Adddress, this.Port, linkedTokenSource.Token); + this.Elapsed = stopWatch.Elapsed; } catch (Exception) { cancellationToken.ThrowIfCancellationRequested(); - return new IPAddressElapsed(address, TimeSpan.MaxValue); + this.Elapsed = TimeSpan.MaxValue; } finally { + this.lastTestTickCount = Environment.TickCount64; stopWatch.Stop(); } } + + public bool Equals(IPAddressElapsed? other) + { + return other != null && other.Adddress.Equals(this.Adddress); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is IPAddressElapsed other && this.Equals(other); + } + + public override int GetHashCode() + { + return this.Adddress.GetHashCode(); + } + + public override string ToString() + { + return this.Adddress.ToString(); + } } } diff --git a/FastGithub.DomainResolve/IPAddressElapsedCollection.cs b/FastGithub.DomainResolve/IPAddressElapsedCollection.cs deleted file mode 100644 index f05295b..0000000 --- a/FastGithub.DomainResolve/IPAddressElapsedCollection.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace FastGithub.DomainResolve -{ - /// - /// IP延时集合 - /// - [DebuggerDisplay("Count={Count} IsExpired={IsExpired}")] - sealed class IPAddressElapsedCollection : IEnumerable - { - private readonly List addressElapseds; - private readonly int creationTickCount = Environment.TickCount; - private static readonly int maxLifeTime = 60 * 1000; - - /// - /// 获取空的 - /// - public static IPAddressElapsedCollection Empty = new(); - - /// - /// 获取数量 - /// - public int Count => this.addressElapseds.Count; - - /// - /// 获取是否为空 - /// - public bool IsEmpty => this.addressElapseds.Count == 0; - - /// - /// 获取是否已过期 - /// - public bool IsExpired => Environment.TickCount - this.creationTickCount > maxLifeTime; - - /// - /// IP延时集合 - /// - private IPAddressElapsedCollection() - { - this.addressElapseds = new List(); - this.creationTickCount = 0; - } - - /// - /// IP延时集合 - /// - /// - public IPAddressElapsedCollection(IPAddressElapsed addressElapsed) - { - this.addressElapseds = new List { addressElapsed }; - } - - /// - /// IP延时集合 - /// - /// - public IPAddressElapsedCollection(IEnumerable addressElapseds) - { - this.addressElapseds = addressElapseds.OrderBy(item => item.Elapsed).ToList(); - } - - /// - /// 获取迭代器 - /// - /// - public IEnumerator GetEnumerator() - { - return this.addressElapseds.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return this.addressElapseds.GetEnumerator(); - } - - public override string ToString() - { - return $"[{string.Join(", ", this.addressElapseds.Select(item => item.Adddress))}]"; - } - } -}