为什么我不能取消CFHost Info Resolution?

时间:2013-04-17 14:36:56

标签: macos network-programming core-services

AFAIK CFHost在OS X(和iOS)上提供唯一的公共API ,用于解析异步和/或可以取消的DNS解析(因此可以实现自定义超时) )。所有其他API都是同步的,无法取消,因此每个DNS查找都必须浪费一个线程以使操作异步或可停止(即使是Grand Central Dispatch也会在每个查询中浪费一个线程,你只需要不必自己创建线程。每个DNS解析调用有一个阻塞线程(并且这样的调用可以阻塞相当长的时间,在我的系统上超时是在调用最终超时之前的30秒),如果你需要解析大量的DNS,那真的不是一种方法主机名。

{p> CFHost对我来说似乎是一个很好的工作。它可以同步使用,在这种情况下,文档说阻塞请求可以从另一个线程中取消,它可以异步使用,在这种情况下请求在后台运行,如果需要也可以取消,但它在成功或自然超时之前不会阻止任何线程。内部CFHost使用getaddrinfo_async_*函数,但这不是公共API,据我所知,这些函数是私有的,不应该直接使用它们。

所以这里是我编写的一个简单的代码,用于使用cancel来测试CFHost查找,但它没有按预期工作,我不明白为什么。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <dispatch/dispatch.h>
#include <CoreServices/CoreServices.h>

int main (int argc, char ** argv ) {
    CFHostRef host;
    dispatch_time_t timeout;
    CFAbsoluteTime startTime;
    dispatch_queue_t timeoutQueue;

    startTime = CFAbsoluteTimeGetCurrent();

    host = CFHostCreateWithName(kCFAllocatorDefault, CFSTR("www.apple.com"));
    assert(host);

    timeout = dispatch_time(DISPATCH_TIME_NOW, 5 * 1000 * 1000 * 1000ull);
    timeoutQueue = dispatch_get_global_queue(
        DISPATCH_QUEUE_PRIORITY_DEFAULT, 0
    );
    assert(timeoutQueue);

    dispatch_after(timeout, timeoutQueue,
        ^{
            printf("%u: Timeout limit reached, canceling.\n",
                (unsigned)(CFAbsoluteTimeGetCurrent() - startTime)
            );
            CFHostCancelInfoResolution(host, kCFHostAddresses);
        }
    );

    printf("%u: Starting name resolution.\n",
        (unsigned)(CFAbsoluteTimeGetCurrent() - startTime)
    );
    CFHostStartInfoResolution(host, kCFHostAddresses, NULL);
    printf("%u: Name resolution terminated.\n",
        (unsigned)(CFAbsoluteTimeGetCurrent() - startTime)
    );

    return 0;
}

如果DNS服务器配置正确,此代码将很快解析名称:

0: Starting name resolution.
0: Name resolution terminated.

这是预期的。但是,如果我在系统中“错误配置”DNS,那么所有DNS查询都会超时,这就是我得到的:

0: Starting name resolution.
5: Timeout limit reached, canceling.
30: Name resolution terminated.

5秒后命中取消计时器并取消请求,但请求不会停止,它将再次阻止25秒。实际上,如果我不取消请求,它也会阻塞30秒,因为,正如我上面所说,这是我的系统的自然DNS超时。因此,对CFHostCancelInfoResolution的调用完全是 NOTHING

引用Apple的CFHost文档:

  

CFHostStartInfoResolution

     

[...]

     

在同步模式下,此功能会一直阻止,直到分辨率为止   完成后,在这种情况下此函数返回TRUE,直到   通过调用CFHostCancelInfoResolution来停止分辨率   另一个线程,在这种情况下,此函数返回FALSE,或直到   发生错误。

好的,我从另一个线程调用CFHostCancelInfoResolution,但该函数仍然阻塞。这可能是API中的错误,文档中的错误,或者我是非常愚蠢的正确使用此API,并且有一些非常基本的我在这里忽略。

更新

这实际上可能是一个错误。我刚刚在10.6上测试了上面的代码,它完全按预期工作,5秒后取消查找。在10.7和10.8上,取消调用不执行任何操作,代码将阻塞,直到达到正常的DNS超时。

0 个答案:

没有答案