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);