Browse Source

使用Tcp Connect取代ping测速

老九 3 years ago
parent
commit
d3f5a46753

+ 32 - 25
FastGithub.DomainResolve/DnsClient.cs

@@ -11,7 +11,7 @@ using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
-using System.Net.NetworkInformation;
+using System.Net.Sockets;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -34,6 +34,7 @@ namespace FastGithub.DomainResolve
         private readonly IMemoryCache dnsCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
         private readonly IMemoryCache dnsCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
         private readonly TimeSpan defaultEmptyTtl = TimeSpan.FromSeconds(30d);
         private readonly TimeSpan defaultEmptyTtl = TimeSpan.FromSeconds(30d);
         private readonly int resolveTimeout = (int)TimeSpan.FromSeconds(2d).TotalMilliseconds;
         private readonly int resolveTimeout = (int)TimeSpan.FromSeconds(2d).TotalMilliseconds;
+        private static readonly TimeSpan maxConnectTimeout = TimeSpan.FromSeconds(2d);
 
 
         private record LookupResult(IPAddress[] Addresses, TimeSpan TimeToLive);
         private record LookupResult(IPAddress[] Addresses, TimeSpan TimeToLive);
 
 
@@ -56,15 +57,15 @@ namespace FastGithub.DomainResolve
         /// <summary>
         /// <summary>
         /// 解析域名
         /// 解析域名
         /// </summary>
         /// </summary>
-        /// <param name="domain">域名</param>
+        /// <param name="endPoint">远程结节</param>
         /// <param name="cancellationToken"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         /// <returns></returns>
-        public async IAsyncEnumerable<IPAddress> ResolveAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken)
+        public async IAsyncEnumerable<IPAddress> ResolveAsync(DnsEndPoint endPoint, [EnumeratorCancellation] CancellationToken cancellationToken)
         {
         {
             var hashSet = new HashSet<IPAddress>();
             var hashSet = new HashSet<IPAddress>();
             foreach (var dns in this.GetDnsServers())
             foreach (var dns in this.GetDnsServers())
             {
             {
-                var addresses = await this.LookupAsync(dns, domain, cancellationToken);
+                var addresses = await this.LookupAsync(dns, endPoint, cancellationToken);
                 foreach (var address in addresses)
                 foreach (var address in addresses)
                 {
                 {
                     if (hashSet.Add(address) == true)
                     if (hashSet.Add(address) == true)
@@ -98,12 +99,12 @@ namespace FastGithub.DomainResolve
         /// 解析域名
         /// 解析域名
         /// </summary>
         /// </summary>
         /// <param name="dns"></param>
         /// <param name="dns"></param>
-        /// <param name="domain"></param>
+        /// <param name="endPoint"></param>
         /// <param name="cancellationToken"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         /// <returns></returns>
-        private async Task<IPAddress[]> LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default)
+        private async Task<IPAddress[]> LookupAsync(IPEndPoint dns, DnsEndPoint endPoint, CancellationToken cancellationToken = default)
         {
         {
-            var key = $"{dns}:{domain}";
+            var key = $"{dns}/{endPoint}";
             var semaphore = this.semaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
             var semaphore = this.semaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
             await semaphore.WaitAsync(CancellationToken.None);
             await semaphore.WaitAsync(CancellationToken.None);
 
 
@@ -114,22 +115,22 @@ namespace FastGithub.DomainResolve
                     return value;
                     return value;
                 }
                 }
 
 
-                var result = await this.LookupCoreAsync(dns, domain, cancellationToken);
+                var result = await this.LookupCoreAsync(dns, endPoint, cancellationToken);
                 this.dnsCache.Set(key, result.Addresses, result.TimeToLive);
                 this.dnsCache.Set(key, result.Addresses, result.TimeToLive);
 
 
                 var items = string.Join(", ", result.Addresses.Select(item => item.ToString()));
                 var items = string.Join(", ", result.Addresses.Select(item => item.ToString()));
-                this.logger.LogInformation($"dns://{dns}:{domain}->[{items}]");
+                this.logger.LogInformation($"dns://{dns}:{endPoint}->[{items}]");
 
 
                 return result.Addresses;
                 return result.Addresses;
             }
             }
             catch (OperationCanceledException)
             catch (OperationCanceledException)
             {
             {
-                this.logger.LogInformation($"dns://{dns}无法解析{domain}:请求超时");
+                this.logger.LogInformation($"dns://{dns}无法解析{endPoint}:请求超时");
                 return Array.Empty<IPAddress>();
                 return Array.Empty<IPAddress>();
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
-                this.logger.LogWarning($"dns://{dns}无法解析{domain}:{ex.Message}");
+                this.logger.LogWarning($"dns://{dns}无法解析{endPoint}:{ex.Message}");
                 return Array.Empty<IPAddress>();
                 return Array.Empty<IPAddress>();
             }
             }
             finally
             finally
@@ -142,12 +143,12 @@ namespace FastGithub.DomainResolve
         /// 解析域名
         /// 解析域名
         /// </summary>
         /// </summary>
         /// <param name="dns"></param>
         /// <param name="dns"></param>
-        /// <param name="domain"></param>
+        /// <param name="endPoint"></param>
         /// <param name="cancellationToken"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         /// <returns></returns>
-        private async Task<LookupResult> LookupCoreAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default)
+        private async Task<LookupResult> LookupCoreAsync(IPEndPoint dns, DnsEndPoint endPoint, CancellationToken cancellationToken = default)
         {
         {
-            if (domain == LOCALHOST)
+            if (endPoint.Host == LOCALHOST)
             {
             {
                 return new LookupResult(new[] { IPAddress.Loopback }, TimeSpan.MaxValue);
                 return new LookupResult(new[] { IPAddress.Loopback }, TimeSpan.MaxValue);
             }
             }
@@ -162,7 +163,7 @@ namespace FastGithub.DomainResolve
                 OperationCode = OperationCode.Query
                 OperationCode = OperationCode.Query
             };
             };
 
 
-            request.Questions.Add(new Question(new Domain(domain), RecordType.A));
+            request.Questions.Add(new Question(new Domain(endPoint.Host), RecordType.A));
             var clientRequest = new ClientRequest(resolver, request);
             var clientRequest = new ClientRequest(resolver, request);
             var response = await clientRequest.Resolve(cancellationToken);
             var response = await clientRequest.Resolve(cancellationToken);
 
 
@@ -179,7 +180,7 @@ namespace FastGithub.DomainResolve
 
 
             if (addresses.Length > 1)
             if (addresses.Length > 1)
             {
             {
-                addresses = await OrderByPingAnyAsync(addresses);
+                addresses = await OrderByConnectAnyAsync(addresses, endPoint.Port, cancellationToken);
             }
             }
 
 
             var timeToLive = response.AnswerRecords.First().TimeToLive;
             var timeToLive = response.AnswerRecords.First().TimeToLive;
@@ -190,15 +191,17 @@ namespace FastGithub.DomainResolve
 
 
             return new LookupResult(addresses, timeToLive);
             return new LookupResult(addresses, timeToLive);
         }
         }
-
         /// <summary>
         /// <summary>
-        /// ping排序
+        /// 连接速度排序
         /// </summary>
         /// </summary>
         /// <param name="addresses"></param>
         /// <param name="addresses"></param>
+        /// <param name="port"></param>
+        /// <param name="cancellationToken"></param>
         /// <returns></returns>
         /// <returns></returns>
-        private static async Task<IPAddress[]> OrderByPingAnyAsync(IPAddress[] addresses)
+        private static async Task<IPAddress[]> OrderByConnectAnyAsync(IPAddress[] addresses, int port, CancellationToken cancellationToken)
         {
         {
-            var fastedAddress = await await Task.WhenAny(addresses.Select(address => PingAsync(address)));
+            var tasks = addresses.Select(address => ConnectAsync(address, port, cancellationToken));
+            var fastedAddress = await await Task.WhenAny(tasks);
             if (fastedAddress == null)
             if (fastedAddress == null)
             {
             {
                 return addresses;
                 return addresses;
@@ -216,17 +219,21 @@ namespace FastGithub.DomainResolve
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// ping请求
+        /// 连接指定ip和端口
         /// </summary>
         /// </summary>
         /// <param name="address"></param>
         /// <param name="address"></param>
+        /// <param name="port"></param>
+        /// <param name="cancellationToken"></param>
         /// <returns></returns>
         /// <returns></returns>
-        private static async Task<IPAddress?> PingAsync(IPAddress address)
+        private static async Task<IPAddress?> ConnectAsync(IPAddress address, int port, CancellationToken cancellationToken)
         {
         {
             try
             try
             {
             {
-                using var ping = new Ping();
-                var reply = await ping.SendPingAsync(address);
-                return reply.Status == IPStatus.Success ? address : default;
+                using var timeoutTokenSource = new CancellationTokenSource(maxConnectTimeout);
+                using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
+                using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
+                await socket.ConnectAsync(address, port, linkedTokenSource.Token);
+                return address;
             }
             }
             catch (Exception)
             catch (Exception)
             {
             {

+ 2 - 2
FastGithub.DomainResolve/DomainResolver.cs

@@ -71,7 +71,7 @@ namespace FastGithub.DomainResolve
             else
             else
             {
             {
                 this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty);
                 this.dnsEndPointAddressElapseds.TryAdd(endPoint, IPAddressElapsedCollection.Empty);
-                await foreach (var adddress in this.dnsClient.ResolveAsync(endPoint.Host, cancellationToken))
+                await foreach (var adddress in this.dnsClient.ResolveAsync(endPoint, cancellationToken))
                 {
                 {
                     yield return adddress;
                     yield return adddress;
                 }
                 }
@@ -91,7 +91,7 @@ namespace FastGithub.DomainResolve
                 {
                 {
                     var dnsEndPoint = keyValue.Key;
                     var dnsEndPoint = keyValue.Key;
                     var addresses = new List<IPAddress>();
                     var addresses = new List<IPAddress>();
-                    await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint.Host, cancellationToken))
+                    await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint, cancellationToken))
                     {
                     {
                         addresses.Add(adddress);
                         addresses.Add(adddress);
                     }
                     }

+ 2 - 2
FastGithub.DomainResolve/IPAddressElapsed.cs

@@ -13,7 +13,7 @@ namespace FastGithub.DomainResolve
     [DebuggerDisplay("Adddress={Adddress} Elapsed={Elapsed}")]
     [DebuggerDisplay("Adddress={Adddress} Elapsed={Elapsed}")]
     struct IPAddressElapsed
     struct IPAddressElapsed
     {
     {
-        private static readonly TimeSpan connectTimeout = TimeSpan.FromSeconds(5d);
+        private static readonly TimeSpan maxConnectTimeout = TimeSpan.FromSeconds(5d);
 
 
         /// <summary>
         /// <summary>
         /// 获取IP地址
         /// 获取IP地址
@@ -48,7 +48,7 @@ namespace FastGithub.DomainResolve
             var stopWatch = Stopwatch.StartNew();
             var stopWatch = Stopwatch.StartNew();
             try
             try
             {
             {
-                using var timeoutTokenSource = new CancellationTokenSource(connectTimeout);
+                using var timeoutTokenSource = new CancellationTokenSource(maxConnectTimeout);
                 using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
                 using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
                 using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                 using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                 await socket.ConnectAsync(address, port, linkedTokenSource.Token);
                 await socket.ConnectAsync(address, port, linkedTokenSource.Token);