【发布时间】:2011-08-29 09:49:57
【问题描述】:
(这是一项正在进行的工作。我想知道是否有人可以改进它)
在 Objective C 中,使用 NSHost 解析主机名很容易。
[[NSHost hostWithName:@"www.google.com"] address]
遗憾的是,iOS (iPhone) 仅包含一个私有版本的 NSHost。
我发现了许多使用其他对象或方法执行此操作的方法,但所有这些方法都只在结果中得到 IPv4 地址。所以这是目前我找到的唯一有效的方法。
我第一次尝试像bdunagan一样使用异步CFHostStartInfoResolution,但未能使其适应IPv6。
你们中的一些人会喜欢让一个方法工作,所以这里是一个,但如果你知道一种异步的方法,我会很高兴了解它......因为目前我使用弹出窗口来提醒蜂窝连接速度较慢时可能发生的下一次冻结
/**
Give the IPs corresponding to a Hostname
Sometime only 1 IPv4 is shown even if there's more.
Sometime only 1 IPv6 is shown even if there's more.
Certainly due to iOS Memory optimisation when locally cached
@author Christian Gonzalvez, http://wiki.gonzofamily.com
@param hostName A hostname
@return an Array of NSString of all the corresponding IP addresses. The first
is the Canonical name, the following are IPs (all NSString)
*/
+ (NSArray *)addressesForHostname:(NSString *)hostname
{
const char* hostnameC = [hostname UTF8String];
struct addrinfo hints, *res;
struct sockaddr_in *s4;
struct sockaddr_in6 *s6;
int retval;
char buf[64];
NSMutableArray *result; //the array which will be return
NSMutableArray *result4; //the array of IPv4, to order them at the end
NSString *previousIP = nil;
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = PF_UNSPEC;//AF_INET6;
hints.ai_flags = AI_CANONNAME;
//AI_ADDRCONFIG, AI_ALL, AI_CANONNAME, AI_NUMERICHOST
//AI_NUMERICSERV, AI_PASSIVE, OR AI_V4MAPPED
retval = getaddrinfo(hostnameC, NULL, &hints, &res);
if (retval == 0)
{
if (res->ai_canonname)
{
result = [NSMutableArray arrayWithObject:[NSString stringWithUTF8String:res->ai_canonname]];
}
else
{
//it means the DNS didn't know this host
return nil;
}
result4= [NSMutableArray array];
while (res) {
switch (res->ai_family){
case AF_INET6:
s6 = (struct sockaddr_in6 *)res->ai_addr;
if(inet_ntop(res->ai_family, (void *)&(s6->sin6_addr), buf, sizeof(buf))
== NULL)
{
NSLog(@"inet_ntop failed for v6!\n");
}
else
{
//surprisingly every address is in double, let's add this test
if (![previousIP isEqualToString:[NSString stringWithUTF8String:buf]]) {
[result addObject:[NSString stringWithUTF8String:buf]];
}
}
break;
case AF_INET:
s4 = (struct sockaddr_in *)res->ai_addr;
if(inet_ntop(res->ai_family, (void *)&(s4->sin_addr), buf, sizeof(buf))
== NULL)
{
NSLog(@"inet_ntop failed for v4!\n");
}
else
{
//surprisingly every address is in double, let's add this test
if (![previousIP isEqualToString:[NSString stringWithUTF8String:buf]]) {
[result4 addObject:[NSString stringWithUTF8String:buf]];
}
}
break;
default:
NSLog(@"Neither IPv4 nor IPv6!");
}
//surprisingly every address is in double, let's add this test
previousIP = [NSString stringWithUTF8String:buf];
res = res->ai_next;
}
}else{
NSLog(@"no IP found");
return nil;
}
return [result arrayByAddingObjectsFromArray:result4];
}
注意:我注意到大多数时候只返回 1 个 IPv6,我怀疑这是由于本地缓存时 iOS 内存优化造成的。如果你一次又一次地运行这个方法,有时你有 3 个 IPv6,但你只有 1 个 IPv4。
【问题讨论】:
-
...为什么不能在后台线程上执行该选择器?也许我有点密集......
-
我开始阅读有关线程的 Apple 文档,它们(不是一点点)密集。还没有找到一个简单的例子。你知道线程吗?我开始认为文档的复杂性不值得花时间。如果您认为这是解决方案,我会这样做并更正这篇文章。
标签: iphone objective-c ios dns ipv6