有没有办法在 swift 或 ObjC 中为 IPv4 和 IPv6 发出单独的 DNS 请求
Is there a way to make separate DNS requests for IPv4 and IPv6 in swift or ObjC
我目前拥有的是:
void startQueryIPv4(const char *hostName){
printf("startQueryIPv4");
DNSServiceRef serviceRef;
DNSServiceGetAddrInfo(&serviceRef, kDNSServiceFlagsForceMulticast, 0, kDNSServiceProtocol_IPv4, hostName, queryIPv4Callback, NULL);
DNSServiceProcessResult(serviceRef);
DNSServiceRefDeallocate(serviceRef);
}
static void queryIPv4Callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context){
printf("queryIPv4Callback");
if (errorCode == kDNSServiceErr_NoError) {
printf("no error");
char *theAddress = NULL;
switch(address->sa_family) {
case AF_INET: {
struct sockaddr_in *addr_in = (struct sockaddr_in *)address;
theAddress = malloc(INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(addr_in->sin_addr), theAddress, INET_ADDRSTRLEN);
break;
}
case AF_INET6: {
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)address;
theAddress = malloc(INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), theAddress, INET6_ADDRSTRLEN);
break;
}
default:
break;
}
printf("IP address: %s\n", theAddress);
free(theAddress);
} else {
printf("%d", errorCode);
}
}
但从未调用回调。
在控制台中,我收到此错误:TIC Read Status [9:0x0]: 1:57
ObjectiveC 不是我的力量,但我不得不搞砸它。任何帮助将不胜感激。
因为 Objective-C 是 C 的真正超集并且 Darwin 被证明与 SUS 3 兼容,所以您的 Objective-C 程序 iOS 应该能够使用 C 接口到系统的名称解析器:getaddrinfo()
。您可以使用此函数的第三个参数来指定您只需要 IPv4 结果(或只需要 IPv6 结果)。
你应该知道的事情:
这当然是一个同步接口;如果你想要异步,那么你需要自己安排。
getaddrinfo()
分配和 returns 一个地址链表,所以
原则上,您可能需要检查多个
您需要在完成后通过 freeaddrinfo()
释放列表
您没有收到回调的原因是您没有使用调度队列。 DNSServiceGetAddrInfo API 是异步的。如果您在 Apple 设备上执行此操作,您需要更像这样的东西:
void startQueryIPv4(const char *hostName) {
printf("startQueryIPv4");
DNSServiceRef serviceRef;
DNSServiceGetAddrInfo(&serviceRef, kDNSServiceFlagsForceMulticast, 0, kDNSServiceProtocol_IPv4, hostName, queryIPv4Callback, NULL);
main_queue = dispatch_get_main_queue();
DNSServiceSetDispatchQueue(sdref, main_queue);
dispatch_main();
}
注意 dispatch_main() 是 libdispatch 的主要事件循环:如果你想做其他事情,你需要在调度循环中安排它,因为 dispatch_main() 不会return.
在您的原始代码中,您调用了 DNSServiceRefDeallocate(),但是在您想要停止查询之前您不能这样做。如果您在开始查询后立即调用它,它将取消查询。所以例如你可以从回调中调用它。
但是,更好的流程是执行长期查询 (kDNSServiceFlagsLongLivedQuery),以便在信息发生变化时获得更新。当然,您随后需要更改要连接的主机,因此只有在您的应用程序将长时间连接时才这样做。
此外,您可能会得到不止一个答案。如果这样做,则可能是某些答案有助于建立联系,而其他答案则不然。因此,您可能希望积累答案并尝试每一个,而不是如果您得到的第一个答案不起作用就放弃。如果立即有更多数据,回调将包括 kDNSServiceFlagsMoreComing 标志。每次回调被调用时,它都会得到一个答案(或以某种方式表明查询失败)。
当然,这是一个相当低级的API。如果你想让你的生活更轻松一些,你应该使用网络框架。 Network Framework 为您做了“快乐的眼球”部分——尝试每个响应直到它获得连接,然后 return 向您发送它获得的连接,取消其他连接。
但是你没有问这个,这里就不多说了。
我目前拥有的是:
void startQueryIPv4(const char *hostName){
printf("startQueryIPv4");
DNSServiceRef serviceRef;
DNSServiceGetAddrInfo(&serviceRef, kDNSServiceFlagsForceMulticast, 0, kDNSServiceProtocol_IPv4, hostName, queryIPv4Callback, NULL);
DNSServiceProcessResult(serviceRef);
DNSServiceRefDeallocate(serviceRef);
}
static void queryIPv4Callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context){
printf("queryIPv4Callback");
if (errorCode == kDNSServiceErr_NoError) {
printf("no error");
char *theAddress = NULL;
switch(address->sa_family) {
case AF_INET: {
struct sockaddr_in *addr_in = (struct sockaddr_in *)address;
theAddress = malloc(INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(addr_in->sin_addr), theAddress, INET_ADDRSTRLEN);
break;
}
case AF_INET6: {
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)address;
theAddress = malloc(INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), theAddress, INET6_ADDRSTRLEN);
break;
}
default:
break;
}
printf("IP address: %s\n", theAddress);
free(theAddress);
} else {
printf("%d", errorCode);
}
}
但从未调用回调。 在控制台中,我收到此错误:TIC Read Status [9:0x0]: 1:57 ObjectiveC 不是我的力量,但我不得不搞砸它。任何帮助将不胜感激。
因为 Objective-C 是 C 的真正超集并且 Darwin 被证明与 SUS 3 兼容,所以您的 Objective-C 程序 iOS 应该能够使用 C 接口到系统的名称解析器:getaddrinfo()
。您可以使用此函数的第三个参数来指定您只需要 IPv4 结果(或只需要 IPv6 结果)。
你应该知道的事情:
这当然是一个同步接口;如果你想要异步,那么你需要自己安排。
getaddrinfo()
分配和 returns 一个地址链表,所以原则上,您可能需要检查多个
您需要在完成后通过
freeaddrinfo()
释放列表
您没有收到回调的原因是您没有使用调度队列。 DNSServiceGetAddrInfo API 是异步的。如果您在 Apple 设备上执行此操作,您需要更像这样的东西:
void startQueryIPv4(const char *hostName) {
printf("startQueryIPv4");
DNSServiceRef serviceRef;
DNSServiceGetAddrInfo(&serviceRef, kDNSServiceFlagsForceMulticast, 0, kDNSServiceProtocol_IPv4, hostName, queryIPv4Callback, NULL);
main_queue = dispatch_get_main_queue();
DNSServiceSetDispatchQueue(sdref, main_queue);
dispatch_main();
}
注意 dispatch_main() 是 libdispatch 的主要事件循环:如果你想做其他事情,你需要在调度循环中安排它,因为 dispatch_main() 不会return.
在您的原始代码中,您调用了 DNSServiceRefDeallocate(),但是在您想要停止查询之前您不能这样做。如果您在开始查询后立即调用它,它将取消查询。所以例如你可以从回调中调用它。
但是,更好的流程是执行长期查询 (kDNSServiceFlagsLongLivedQuery),以便在信息发生变化时获得更新。当然,您随后需要更改要连接的主机,因此只有在您的应用程序将长时间连接时才这样做。
此外,您可能会得到不止一个答案。如果这样做,则可能是某些答案有助于建立联系,而其他答案则不然。因此,您可能希望积累答案并尝试每一个,而不是如果您得到的第一个答案不起作用就放弃。如果立即有更多数据,回调将包括 kDNSServiceFlagsMoreComing 标志。每次回调被调用时,它都会得到一个答案(或以某种方式表明查询失败)。
当然,这是一个相当低级的API。如果你想让你的生活更轻松一些,你应该使用网络框架。 Network Framework 为您做了“快乐的眼球”部分——尝试每个响应直到它获得连接,然后 return 向您发送它获得的连接,取消其他连接。
但是你没有问这个,这里就不多说了。