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

Mec*_*cki 6 macos network-programming core-services

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

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

所以这里有一段简单的代码我CFHost用cancel 来测试查找,但它没有按预期工作,我不明白为什么.

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

0: Starting name resolution.
0: Name resolution terminated.
Run Code Online (Sandbox Code Playgroud)

这是预料之中的.但是,如果我在系统中"错误配置"DNS,那么所有DNS查询都会超时,这是我得到的:

0: Starting name resolution.
5: Timeout limit reached, canceling.
30: Name resolution terminated.
Run Code Online (Sandbox Code Playgroud)

5秒后命中取消计时器,我取消请求,但请求不会停止,它将再次阻止25秒.实际上,如果我不取消请求,它也会阻塞30秒,因为,正如我上面所说,这是我的系统的自然DNS超时.所以呼吁CFHostCancelInfoResolution完全没有.

引用Apple的CFHost文档:

CFHostStartInfoResolution

[...]

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

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

更新

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