首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >仅在IPv6上使用iOS的DNS解析同步?

仅在IPv6上使用iOS的DNS解析同步?
EN

Stack Overflow用户
提问于 2011-05-20 06:02:23
回答 2查看 2.2K关注 0票数 2

(这是一项正在进行的工作。我想知道是否有人能改进它)

在目标C中,使用NSHost很容易解析主机名。

代码语言:javascript
复制
[[NSHost hostWithName:@"www.google.com"] address]

可悲的是,iOS (iPhone)只包含NSHost的一个私有版本。

我在其他对象或方法中找到了许多方法来实现这一点,但是所有这些方法都只在结果中获得了IPv4地址。所以现在我发现的唯一有效的方法就是。

我第一次尝试使用异步CFHostStartInfoResolution,就像布杜纳根一样,但未能使其适应IPv6。

你们中的一些人会感激得到一个方法的工作,所以这里有一个,但如果你们知道一种方式将是异步的,我会很感激了解它。因为目前,我使用弹出窗口来警告下一次由于缓慢的细胞连接可能发生的冻结。

代码语言:javascript
复制
/**
 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];
}

注意:我注意到大多数情况下只返回一个IPv6,我怀疑这是由于本地缓存时iOS内存优化所致。如果您一次又一次地运行此方法,有时您有3 IPv6,但是只有1 IPv4。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-05-20 18:41:47

如果希望在后台线程上运行方法,最简单的方法是使用performSelectorInBackground:withObject:;这是NSObject的实例方法,因此任何对象都可以使用它而不需要任何额外的工作(有趣的是,包括类对象,这在本例中是很好的,因为这是一个类方法):

代码语言:javascript
复制
[[self class] performSelectorInBackground:@selector(addressesForHostName:) 
                               withObject:theHostName];

在该方法中,您需要为线程设置一个自动释放池。您还需要设置某种回调方法来将返回值返回到主线程。确保不尝试在后台线程上执行任何GUI活动。在主线程上这样做是安全的。

代码语言:javascript
复制
+ (NSArray *)addressesForHostname:(NSString *)hostname
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Do your stuff...

    // Wait until done to allow memory to be managed properly
    // If we did not do this, the array might be deallocated
    // before the main thread had a chance to retain it
    [self performSelectorOnMainThread:@selector(addressesCallback:)
                              withObject:[result arrayByAddingObjectsFromArray:result4]
                           waitUntilDone:YES];
    // Inside a class method, self refers to the class object.

    [pool drain];
}

如果您一开始没有在主线程上,或者如果您需要更多的控制,您也可以查看NSOperation,它更强大,因此需要更多的工作。不过,它仍然比显式线程管理更容易!

希望这能解决你的问题。听起来就像让这个方法做你需要的,你只需要它不阻塞主线程。

票数 1
EN

Stack Overflow用户

发布于 2011-05-23 02:15:54

多亏了乔什,我才能做到,但以下是我必须做的:

而不是直接调用

代码语言:javascript
复制
self.ipAddressesString = [CJGIpAddress addressesForHostname:@"www.google.com"];

我打电话

代码语言:javascript
复制
[self resolveNow:@"www.google.com"];

并创建3种新方法:

代码语言:javascript
复制
- (void)resolveNow:(NSString *)hostname
{
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    [self performSelectorInBackground:@selector(hostname2ipAddresses:) 
                                   withObject:hostname];
}

- (void)hostname2ipAddresses:(NSString *)hostname
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      //Here is my previous lonely line !! safely started in an other thread
    self.ipAddressesString = [CJGIpAddress addressesForHostname:hostname];
    [self performSelectorOnMainThread:@selector(resolutionDidFinish)
                           withObject:nil
                        waitUntilDone:YES];
    [pool drain];
}

- (void)resolutionDidFinish
{
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    //My STUFF with self.ipAddressesString (now filled)
}

编辑:在实践中,我在一个模型中使用了所有这些,所以当我在解析结束之前关闭视图时,我就崩溃了

因此,在视图中,我添加了dealloc,这是避免崩溃的必要条件。

代码语言:javascript
复制
- (void)dealloc
{
    self.model.delegate = nil;
    [super dealloc];
}

然后-在模型中-我在做任何事情之前测试委托。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6068037

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档