我想检查主机是否可以解析,但我不想等待很长时间,所以我想设置超时。 我试过了
public static bool ResolveTest(string hostNameOrAddress, int millisecond_time_out)
{
var timeoutSpan = TimeSpan.FromMilliseconds(millisecond_time_out);
var result = Dns.BeginGetHostEntry(hostNameOrAddress, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeoutSpan);
if (!success) {
//throw new Exception("Failed to resolve the domain.");
return false;
}
return true;
}
但现在这个工作正常,当它是一个错误的主机时,它也可以返回true。那么如何设置DnsResolve的超时?
答案 0 :(得分:3)
原始答案
查看更新后的答案
无法实际取消Dns.BeginGetHostEntry()
,但您可以尝试实施可在设定时间后取消的内容。这有点hackish但可以按照你的要求做。
然而,DNS查找(通常)非常快,并且测试通常在10ms内解决。
这是一个示例。基本上基于Task
的方法允许您执行Task
,无论结果是否已完成,都会返回bool。
public static Task<bool> Resolve(string hostNameOrAddress, int millisecond_time_out)
{
return Task.Run(async () =>
{
bool completed = false;
var asCallBack = new AsyncCallback(ar =>
{
ResolveState context = (ResolveState)ar.AsyncState;
if (context.Result == ResolveType.Pending)
{
try
{
var ipList = Dns.EndGetHostEntry(ar);
if (ipList == null || ipList.AddressList == null || ipList.AddressList.Length == 0)
context.Result = ResolveType.InvalidHost;
else
context.Result = ResolveType.Completed;
}
catch
{
context.Result = ResolveType.InvalidHost;
}
}
completed = true;
});
ResolveState ioContext = new ResolveState(hostNameOrAddress);
var result = Dns.BeginGetHostEntry(ioContext.HostName, asCallBack, ioContext);
int miliCount = 0;
while (!completed)
{
miliCount++;
if (miliCount >= millisecond_time_out)
{
result.AsyncWaitHandle.Close();
result = null;
ioContext.Result = ResolveType.Timeout;
break;
}
await Task.Delay(1);
}
Console.WriteLine($"The result of {ioContext.HostName} is {ioContext.Result}");
return ioContext.Result == ResolveType.Completed;
});
}
public class ResolveState
{
public ResolveState(string hostName)
{
if (string.IsNullOrWhiteSpace(hostName))
throw new ArgumentNullException(nameof(hostName));
_hostName = hostName;
}
readonly string _hostName;
public ResolveType Result { get; set; } = ResolveType.Pending;
public string HostName => _hostName;
}
public enum ResolveType
{
Pending,
Completed,
InvalidHost,
Timeout
}
然后可以将该方法称为
public static async void RunTest()
{
await Resolve("asdfasdfasdfasdfasdfa.ca", 60);
await Resolve("google.com", 60);
}
执行Resolve后,它会创建一个内部AsyncCallBack
委托。然后将此委托传递给Dns.BeginGetHostEntry()
方法。另外,我们传入state
ResolveState
对象。该状态对象可用于管理上下文之间的状态。因此,当AsyncCallBack
执行时,我们可以设置Result
的{{1}}。接下来,设置ResolveState
标志以指示回调委托已完成。
最后(这是我不喜欢的部分)然后我们有一个执行每completed
的循环,如果超时到期,则将我们的状态对象的1ms
设置为Result
。
这又是一种轻微的hackish,但确实会带来所需的效果。现在这也完成了Timeout
,因此您可以使用async
&amp; async
功能。
更新了答案
在第一个回答后,我不喜欢结果,并回顾了你的初步问题。你在正确的轨道上,除了我们需要像你一样检查完整的旗帜。但是,如果在await
来电后success
未完成,result
将返回false。如果完成,那么WaitOne
将success
(即使没有解析IP地址),您还需要使用true
检查结果。
修订代码:
Dns.EndGetHostEntry
以下是完整的要点https://gist.github.com/Nico-VanHaaster/35342c1386de752674d0c37ceaa65e00。
答案 1 :(得分:0)
作为替代解决方案,NuGet库DNS Client允许配置请求超时。
用法:
var dns = new DnsClient.LookupClient();
dns.Timeout = TimeSpan.FromSeconds(1);
dns.ThrowDnsErrors = true;
//will succeed
var dnsResult1 = dns.GetHostEntry("www.google.com");
//will throw an exception; or, if ThrowDnsErrors is false, return null
var dnsResult2 = dns.GetHostEntry("bogus");
答案 2 :(得分:-1)
当前接受的答案相当古老而复杂,现在您可以通过这种方式轻松使用System.Threading.Tasks.Task.Run()
:
private Task<IPAddress> ResolveAsync(string hostName) {
return System.Threading.Tasks.Task.Run(() => {
return System.Net.Dns.GetHostEntry(hostName).AddressList[0];
});
}
private string ResolveWithTimeout(string hostNameOrIpAddress) {
var timeout = TimeSpan.FromSeconds(3.0);
var task = ResolveAsync(hostNameOrIpAddress);
if (!task.Wait(timeout)) {
throw new TimeoutException();
}
return task.Result.ToString();
}