我想检查一个主机是否可以解析?但我不想等待很长时间;所以我想设置一个超时。
我试过了
public static bool ResolveTest(string hostNameOrAddress, TimeSpan time_out)
{
var result = Dns.BeginGetHostEntry(hostNameOrAddress, null, null);
var success = result.AsyncWaitHandle.WaitOne(time_out);
if (!success) {
//throw new Exception("Failed to resolve the domain.");
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
但这不能正常工作,因为当它是错误的主机时,它也可以返回 true。那么如何设置 DnsResolve 的超时时间呢?
原答案
查看更新的答案
没有办法实际取消,Dns.BeginGetHostEntry()但您可以尝试实现可以在设定时间后取消的东西。这有点骇人听闻,但可以按照您的要求进行。
然而,DNS 查找(通常)非常快,并且在测试中通常会在 10 毫秒内解析。
这是一个示例。基本上制作一个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
}
Run Code Online (Sandbox Code Playgroud)
然后可以将该方法调用为
public static async void RunTest()
{
await Resolve("asdfasdfasdfasdfasdfa.ca", 60);
await Resolve("google.com", 60);
}
Run Code Online (Sandbox Code Playgroud)
当执行 Resolve 时,它会创建一个内部AsyncCallBack委托。然后将该委托传递给该Dns.BeginGetHostEntry()方法。另外我们传入一个state的对象ResolveState。该状态对象负责管理上下文之间的状态。因此,当AsyncCallBack执行时我们可以设置Result的ResolveState。接下来completed设置标志以指示回调委托已完成。
最后(这是我不喜欢的部分)是我们有一个循环执行每个1ms,如果超时到期则将Result我们的状态对象设置为Timeout。
同样,这有点hackish,但确实达到了预期的效果。现在这也已完成,async以便您可以使用async&await功能。
更新答案
在第一个答案之后,我不喜欢这个结果,并回顾了您最初的问题。您走在正确的轨道上,只是我们需要像您一样检查完整的标志。但是,如果调用后未完成,success将返回 false 。如果完成,那么(即使没有解析 IP 地址)您需要使用.resultWaitOnesuccesstrueDns.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;
}
Run Code Online (Sandbox Code Playgroud)
这是完整的要点https://gist.github.com/Nico-VanHaaster/35342c1386de752674d0c37ceaa65e00。
| 归档时间: |
|
| 查看次数: |
3360 次 |
| 最近记录: |