Răsfoiți Sursa

累积可连接的IP

老九 3 ani în urmă
părinte
comite
dd36207241

+ 31 - 30
FastGithub.DomainResolve/DomainResolver.cs

@@ -19,7 +19,7 @@ namespace FastGithub.DomainResolve
         private readonly DnsClient dnsClient;
         private readonly DomainPersistence persistence;
         private readonly ILogger<DomainResolver> logger;
-        private readonly ConcurrentDictionary<DnsEndPoint, IPAddressElapsedCollection> dnsEndPointAddressElapseds = new();
+        private readonly ConcurrentDictionary<DnsEndPoint, IPAddressElapsed[]> dnsEndPointAddressElapseds = new();
 
         /// <summary>
         /// 域名解析器
@@ -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<IPAddressElapsed>());
             }
         }
 
@@ -66,7 +66,7 @@ namespace FastGithub.DomainResolve
         /// <returns></returns>
         public async IAsyncEnumerable<IPAddress> 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<IPAddressElapsed>()))
                 {
                     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<IPAddressElapsed>();
+
+                foreach (var item in keyValue.Value)
                 {
-                    var dnsEndPoint = keyValue.Key;
-                    var addresses = new HashSet<IPAddress>();
-                    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);
-                    }
+                    hashSet.Add(item);
+                }
+
+                await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint, fastSort: false, cancellationToken))
+                {
+                    hashSet.Add(new IPAddressElapsed(adddress, dnsEndPoint.Port));
+                }
 
-                    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);
-                    }
+                var updateTasks = hashSet
+                    .Where(item => item.CanUpdateElapsed())
+                    .Select(item => item.UpdateElapsedAsync(cancellationToken));
 
-                    this.dnsEndPointAddressElapseds[dnsEndPoint] = addressElapseds;
-                    this.logger.LogInformation($"{dnsEndPoint.Host}->{addressElapseds}");
+                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;
             }
         }
     }

+ 55 - 16
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
 {
     /// <summary>
-    /// IP延时
+    /// IP延时记录
+    /// 5分钟有效期
+    /// 5秒连接超时
     /// </summary>
     [DebuggerDisplay("Adddress={Adddress} Elapsed={Elapsed}")]
-    struct IPAddressElapsed
+    sealed class IPAddressElapsed : IEquatable<IPAddressElapsed>
     {
-        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;
 
         /// <summary>
         /// 获取IP地址
         /// </summary>
         public IPAddress Adddress { get; }
 
+        /// <summary>
+        /// 获取端口
+        /// </summary>
+        public int Port { get; }
+
         /// <summary>
         /// 获取延时
         /// </summary>
-        public TimeSpan Elapsed { get; }
+        public TimeSpan Elapsed { get; private set; } = TimeSpan.MaxValue;
 
         /// <summary>
         /// IP延时
         /// </summary>
         /// <param name="adddress"></param>
-        /// <param name="elapsed"></param>
-        public IPAddressElapsed(IPAddress adddress, TimeSpan elapsed)
+        /// <param name="port"></param>
+        public IPAddressElapsed(IPAddress adddress, int port)
         {
             this.Adddress = adddress;
-            this.Elapsed = elapsed;
+            this.Port = port;
         }
 
         /// <summary>
-        /// 获取连接耗
+        /// 是否可以更新延
         /// </summary>
-        /// <param name="address"></param>
-        /// <param name="port"></param>
+        /// <returns></returns>
+        public bool CanUpdateElapsed()
+        {
+            return Environment.TickCount64 - this.lastTestTickCount > maxLifeTime;
+        }
+
+        /// <summary>
+        /// 更新连接耗时
+        /// </summary> 
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public static async Task<IPAddressElapsed> 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();
+        }
     }
 }

+ 0 - 85
FastGithub.DomainResolve/IPAddressElapsedCollection.cs

@@ -1,85 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-
-namespace FastGithub.DomainResolve
-{
-    /// <summary>
-    /// IP延时集合
-    /// </summary>
-    [DebuggerDisplay("Count={Count} IsExpired={IsExpired}")]
-    sealed class IPAddressElapsedCollection : IEnumerable<IPAddressElapsed>
-    {
-        private readonly List<IPAddressElapsed> addressElapseds;
-        private readonly int creationTickCount = Environment.TickCount;
-        private static readonly int maxLifeTime = 60 * 1000;
-
-        /// <summary>
-        /// 获取空的
-        /// </summary>
-        public static IPAddressElapsedCollection Empty = new();
-
-        /// <summary>
-        /// 获取数量
-        /// </summary>
-        public int Count => this.addressElapseds.Count;
-
-        /// <summary>
-        /// 获取是否为空
-        /// </summary>
-        public bool IsEmpty => this.addressElapseds.Count == 0;
-
-        /// <summary>
-        /// 获取是否已过期
-        /// </summary>
-        public bool IsExpired => Environment.TickCount - this.creationTickCount > maxLifeTime;
-
-        /// <summary>
-        /// IP延时集合
-        /// </summary>
-        private IPAddressElapsedCollection()
-        {
-            this.addressElapseds = new List<IPAddressElapsed>();
-            this.creationTickCount = 0;
-        }
-
-        /// <summary>
-        /// IP延时集合
-        /// </summary>
-        /// <param name="addressElapsed"></param>
-        public IPAddressElapsedCollection(IPAddressElapsed addressElapsed)
-        {
-            this.addressElapseds = new List<IPAddressElapsed> { addressElapsed };
-        }
-
-        /// <summary>
-        /// IP延时集合
-        /// </summary>
-        /// <param name="addressElapseds"></param>
-        public IPAddressElapsedCollection(IEnumerable<IPAddressElapsed> addressElapseds)
-        {
-            this.addressElapseds = addressElapseds.OrderBy(item => item.Elapsed).ToList();
-        }
-
-        /// <summary>
-        /// 获取迭代器
-        /// </summary>
-        /// <returns></returns>
-        public IEnumerator<IPAddressElapsed> 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))}]";
-        }
-    }
-}