C#:如何设置DNS解析超时?

Elsonwx

我想检查主机是否可以解决,但是我不想等待很长时间。所以我想设置一个超时时间。

我努力了

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

但这不能正常工作,因为当它是错误的主机时,它也可以返回true。那么如何为DnsResolve设置超时?

尼科

原始答案

看更新的答案

无法实际取消,Dns.BeginGetHostEntry()但您可以尝试实施可以在设置的时间后取消的功能。这有点黑,但是可以按照您的要求进行。

但是,DNS查找(通常)确实非常快,并且在测试中通常可以在10毫秒内解决。

这是一个样本。基本上是Task基于基础的方法,Task无论您是否完成结果,该方法都允许您执行返回布尔值的a。

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

执行解析时,它将创建一个内部AsyncCallBack委托。然后将该委托传递给Dns.BeginGetHostEntry()方法。此外,我们传入的state对象ResolveState该状态对象可用于管理上下文之间的状态。因此,当AsyncCallBack执行执行时,我们可以设置ResultResolveState接下来,completed设置标志以指示回调委托已完成。

最后(这是我不喜欢的部分),然后我们将执行一个循环,每执行一次1ms,如果超时到期,则将Result状态对象的设置为Timeout

再次,这是有点骇人听闻的,但确实可以达到预期的效果。现在也已完成,async因此您可以使用asyncawait功能。

更新的答案

在第一个答案之后,我不喜欢结果,并查看了您的第一个问题。您处在正确的轨道上,只不过我们需要像完成操作一样检查完成标志。但是,success如果调用result后未完成,则将返回false WaitOne如果它完成,然后successtrue(即使没有解决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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章