C#:如何设置DNS解析超时?
我想检查主机是否可以解决,但我不想等很长时间,所以我想设置超时。 我试图C#:如何设置DNS解析超时?
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.So如何设置DnsResolve超时?
原来的答案
看看更新的答案
没有实际上取消Dns.BeginGetHostEntry()
但你可以尝试实现的东西,可以在设定的时间后,被取消的方式。这有些黑客,但可以按照你的要求去做。
但是,DNS查找(通常)非常快,测试通常在10ms内解析。
下面是一个示例。基本上使基于Task
的方法,允许您执行一个Task
返回一个布尔结果是否完成。当执行解析它创建了一个内部AsyncCallBack
代表
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);
}
。然后将该代表传递给Dns.BeginGetHostEntry()
方法。另外我们还通过了state
对象ResolveState
。此状态对象可用于管理上下文之间的状态。因此,当AsyncCallBack
得到执行时,我们可以设置ResolveState
的Result
。接下来,completed
标志被设置为指示回调委托完成。
最后(这是我不喜欢的部分),然后我们有一个循环,每执行和1ms
如果超时设置我们的状态对象的Result
到Timeout
。
这又有点骇人听闻,但确实导致了所需的效果。现在这也是async
,所以你可以使用功能async
& await
功能。
更新回答
我不喜欢的结果,并审查了最初的问题的第一个答案之后。除了我们需要检查完整的标志之外,你们走在了正确的轨道上。但如果result
在WaitOne
调用后未完成,则success
将返回false。如果完成,那么success
将是true
(即使没有解析IP地址),然后您需要使用Dns.EndGetHostEntry
检查结果。
修改后的代码:
public static bool ResolveTest(string hostNameOrAddress, int millisecond_time_out)
{
ResolveState ioContext = new ResolveState(hostNameOrAddress);
var result = Dns.BeginGetHostEntry(ioContext.HostName, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(millisecond_time_out), true);
if (!success)
{
ioContext.Result = ResolveType.Timeout;
}
else
{
try
{
var ipList = Dns.EndGetHostEntry(result);
if (ipList == null || ipList.AddressList == null || ipList.AddressList.Length == 0)
ioContext.Result = ResolveType.InvalidHost;
else
ioContext.Result = ResolveType.Completed;
}
catch
{
ioContext.Result = ResolveType.InvalidHost;
}
}
Console.WriteLine($"The result of ResolveTest for {ioContext.HostName} is {ioContext.Result}");
return ioContext.Result == ResolveType.Completed;
}
下面是完整的要点https://gist.github.com/Nico-VanHaaster/35342c1386de752674d0c37ceaa65e00。
目前公认的答案是很旧的和复杂的,现在你可以很容易地使用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();
}
答案已更新,更好看的版本 – Nico