From d3f5a46753a4607e9bb661bb9c557e35267cc2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E4=B9=9D?= <366193849@qq.com> Date: Sun, 3 Oct 2021 11:28:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8Tcp=20Connect=E5=8F=96?= =?UTF-8?q?=E4=BB=A3ping=E6=B5=8B=E9=80=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.DomainResolve/DnsClient.cs | 57 +++++++++++--------- FastGithub.DomainResolve/DomainResolver.cs | 4 +- FastGithub.DomainResolve/IPAddressElapsed.cs | 4 +- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/FastGithub.DomainResolve/DnsClient.cs b/FastGithub.DomainResolve/DnsClient.cs index 02527bc..9bc6290 100644 --- a/FastGithub.DomainResolve/DnsClient.cs +++ b/FastGithub.DomainResolve/DnsClient.cs @@ -11,7 +11,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; -using System.Net.NetworkInformation; +using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -34,6 +34,7 @@ namespace FastGithub.DomainResolve private readonly IMemoryCache dnsCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); private readonly TimeSpan defaultEmptyTtl = TimeSpan.FromSeconds(30d); private readonly int resolveTimeout = (int)TimeSpan.FromSeconds(2d).TotalMilliseconds; + private static readonly TimeSpan maxConnectTimeout = TimeSpan.FromSeconds(2d); private record LookupResult(IPAddress[] Addresses, TimeSpan TimeToLive); @@ -56,15 +57,15 @@ namespace FastGithub.DomainResolve /// /// 解析域名 /// - /// 域名 + /// 远程结节 /// /// - public async IAsyncEnumerable ResolveAsync(string domain, [EnumeratorCancellation] CancellationToken cancellationToken) + public async IAsyncEnumerable ResolveAsync(DnsEndPoint endPoint, [EnumeratorCancellation] CancellationToken cancellationToken) { var hashSet = new HashSet(); 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) { if (hashSet.Add(address) == true) @@ -98,12 +99,12 @@ namespace FastGithub.DomainResolve /// 解析域名 /// /// - /// + /// /// /// - private async Task LookupAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default) + private async Task 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)); await semaphore.WaitAsync(CancellationToken.None); @@ -114,22 +115,22 @@ namespace FastGithub.DomainResolve 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); 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; } catch (OperationCanceledException) { - this.logger.LogInformation($"dns://{dns}无法解析{domain}:请求超时"); + this.logger.LogInformation($"dns://{dns}无法解析{endPoint}:请求超时"); return Array.Empty(); } catch (Exception ex) { - this.logger.LogWarning($"dns://{dns}无法解析{domain}:{ex.Message}"); + this.logger.LogWarning($"dns://{dns}无法解析{endPoint}:{ex.Message}"); return Array.Empty(); } finally @@ -142,12 +143,12 @@ namespace FastGithub.DomainResolve /// 解析域名 /// /// - /// + /// /// /// - private async Task LookupCoreAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken = default) + private async Task LookupCoreAsync(IPEndPoint dns, DnsEndPoint endPoint, CancellationToken cancellationToken = default) { - if (domain == LOCALHOST) + if (endPoint.Host == LOCALHOST) { return new LookupResult(new[] { IPAddress.Loopback }, TimeSpan.MaxValue); } @@ -162,7 +163,7 @@ namespace FastGithub.DomainResolve 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 response = await clientRequest.Resolve(cancellationToken); @@ -179,7 +180,7 @@ namespace FastGithub.DomainResolve if (addresses.Length > 1) { - addresses = await OrderByPingAnyAsync(addresses); + addresses = await OrderByConnectAnyAsync(addresses, endPoint.Port, cancellationToken); } var timeToLive = response.AnswerRecords.First().TimeToLive; @@ -190,15 +191,17 @@ namespace FastGithub.DomainResolve return new LookupResult(addresses, timeToLive); } - /// - /// ping排序 + /// 连接速度排序 /// /// + /// + /// /// - private static async Task OrderByPingAnyAsync(IPAddress[] addresses) + private static async Task 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) { return addresses; @@ -216,17 +219,21 @@ namespace FastGithub.DomainResolve } /// - /// ping请求 + /// 连接指定ip和端口 /// /// + /// + /// /// - private static async Task PingAsync(IPAddress address) + private static async Task ConnectAsync(IPAddress address, int port, CancellationToken cancellationToken) { 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) { diff --git a/FastGithub.DomainResolve/DomainResolver.cs b/FastGithub.DomainResolve/DomainResolver.cs index 931c44b..999b919 100644 --- a/FastGithub.DomainResolve/DomainResolver.cs +++ b/FastGithub.DomainResolve/DomainResolver.cs @@ -71,7 +71,7 @@ namespace FastGithub.DomainResolve else { 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; } @@ -91,7 +91,7 @@ namespace FastGithub.DomainResolve { var dnsEndPoint = keyValue.Key; var addresses = new List(); - await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint.Host, cancellationToken)) + await foreach (var adddress in this.dnsClient.ResolveAsync(dnsEndPoint, cancellationToken)) { addresses.Add(adddress); } diff --git a/FastGithub.DomainResolve/IPAddressElapsed.cs b/FastGithub.DomainResolve/IPAddressElapsed.cs index 60a6cf9..7df313a 100644 --- a/FastGithub.DomainResolve/IPAddressElapsed.cs +++ b/FastGithub.DomainResolve/IPAddressElapsed.cs @@ -13,7 +13,7 @@ namespace FastGithub.DomainResolve [DebuggerDisplay("Adddress={Adddress} Elapsed={Elapsed}")] struct IPAddressElapsed { - private static readonly TimeSpan connectTimeout = TimeSpan.FromSeconds(5d); + private static readonly TimeSpan maxConnectTimeout = TimeSpan.FromSeconds(5d); /// /// 获取IP地址 @@ -48,7 +48,7 @@ namespace FastGithub.DomainResolve var stopWatch = Stopwatch.StartNew(); try { - using var timeoutTokenSource = new CancellationTokenSource(connectTimeout); + 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);