iOS应用支持IPV6,就那点事儿

作者: 淡淡如水舟 | 来源:发表于2016-05-24 01:26 被阅读115320次

    果然是苹果打个哈欠,iOS行业内就得起一次风暴呀。自从5月初Apple明文规定所有开发者在6月1号以后提交新版本需要支持IPV6-Only的网络,大家便开始热火朝天的研究如何支持IPV6,以及应用中哪些模块目前不支持IPV6。

    为了更好的交流,特建了一个IPV6交流群(群号:574410254),希望能否相互交流沟通问题:

    IPV6支持交流群.png 团队博客公众号-欢迎扫扫码交流.jpg

    一、IPV6-Only支持是啥?

    首先IPV6,是对IPV4地址空间的扩充。目前当我们用iOS设备连接上Wifi、4G、3G等网络时,设备被分配的地址均是IPV4地址,但是随着运营商和企业逐渐部署IPV6 DNS64/NAT64网络之后,设备被分配的地址会变成IPV6的地址,而这些网络就是所谓的IPV6-Only网络,并且仍然可以通过此网络去获取IPV4地址提供的内容。客户端向服务器端请求域名解析,首先通过DNS64 Server查询IPv6的地址,如果查询不到,再向DNS Server查询IPv4地址,通过DNS64 Server合成一个IPV6的地址,最终将一个IPV6的地址返回给客户端。如图所示:

    NAT64-DNS64-ResolutionOfIPv4_2x.png

    在Mac OS 10.11+的双网卡的Mac机器(以太网口+无线网卡),我们可以通过模拟构建这么一个local IPv6 DNS64/NAT64 的网络环境去测试应用是否支持IPV6-Only网络,大概原理如下:

    local_ipv6_dns64_nat64_network_2x.png

    二、Apple如何审核支持IPV6-Only?

    首先第一点:这里说的支持IPV6-Only网络,其实就是说让应用在 IPv6 DNS64/NAT64 网络环境下仍然能够正常运行。但是考虑到我们目前的实际网络环境仍然是IPV4网络,所以应用需要能够同时保证IPV4和IPV6环境下的可用性。从这点来说,苹果不会去扫描IPV4的专有API来拒绝审核通过,因为IPV4的API和IPV6的API调用都会同时存在于代码中(不过为了减小审核被拒风险,建议将IPV4专有API通过IPV6的兼容API来替换)。

    其次第二点:Apple官方声明iOS9开始向IPV6支持过渡,在iOS9.2+支持通过getaddrInfo方法将IPV4地址合成IPV6地址(The ability to synthesize IPv6 addresses was added to getaddrinfo in iOS 9.2 and OS X 10.11.2)。其提供的Reachability库在iOS8系统下,当从IPV4切换到IPV6网络,或者从IPV6网络切换到IPV4,是无法监控到网络状态的变化。也有一些开发者针对这些Bug询问Apple的审核部门,给予的答复是只需要在苹果最新的系统上保证IPV6的兼容性即可

    最后第三点:只要应用的主流程支持IPV6,通过苹果审核即可。对于不支持IPV6的模块,考虑到我们现实IPV6网络的部署还需要一段时间,短时间内不会影响我们用户的使用。但随着4G网络IPV6的部署,这部分模块还是需要逐渐安排人力进行支持。

    追加第四点:如果应用一直直接使用IPV4地址通过NSURLConenction或者NSURLSession进行网络请求(一般需要服务器允许,且客户端需要在header中伪装host);经测试,IPV6网络环境下,直接使用IPV4地址在iOS9及以上的系统仍然能够正常访问;在iOS8.4及以下不能正常访问;这一点苹果的解释和建议是这样的:


    Note: In iOS 9 and OS X 10.11 and later, NSURLSession and CFNetwork automatically synthesize IPv6 addresses from IPv4 literals locally on devices operating on DNS64/NAT64 networks. However, you should still work to rid your code of IP address literals.


    三、应用如何支持IPV6-Only?

    对于如何支持IPV6-Only,官方给出了如下几点标准:(这里就不对其进行解释了,大家看上面的参考链接即可)

    1. Use High-Level Networking Frameworks;
    2. Don’t Use IP Address Literals;
    3. Check Source Code for IPv6 DNS64/NAT64 Incompatibilities;
    4. Use System APIs to Synthesize IPv6 Addresses;
    

    3.1 NSURLConnection是否支持IPV6?

    官方的这句话让我们疑惑顿生:
    *** using high-level networking APIs such as NSURLSession and the CFNetwork frameworks and you connect by name, you should not need to change anything for your app to work with IPv6 addresses***

    只说了NSURLSession和CFNetwork的API不需要改变,但是并没有提及到NSURLConnection。 从上文的参考资料中,我们看到NSURLSession、NSURLConnection同属于Cocoa的url loading system,可以猜测出NSURLConnection在ios9上是支持IPV6的。

    应用里面的API网络请求,大家一般都会选择AFNetworking进行请求发送,由于历史原因,应用的代码基本上都深度引用了AFHTTPRequestOperation类,所以目前API网络请求均需要通过NSURLConnection发送出去,所以必须确认NSURLConnection是否支持IPV6. 经过测试,NSURLConnection在最新的iOS9系统上是支持IPV6的。

    3.2 Cocoa的URL Loading System从iOS哪个版本开始支持IPV6?

    目前我们的应用最低版本还需要支持iOS7,虽然苹果只要求最新版本支持IPV6-Only,但是出于对用户负责的态度,我们仍然需要搞清楚在低版本上URL Loading System的API是否支持IPV6.

    (to fix me, make some experiments)待续~~~

    3.3 Reachability是否需要修改支持IPV6?

    我们可以查到应用中大量使用了Reachability进行网络状态判断,但是在里面却使用了IPV4的专用API。

    在Pods:Reachability中
    AF_INET                  Files:Reachability.m
    struct sockaddr_in       Files:Reachability.h , Reachability.m
    

    那Reachability应该如何支持IPV6呢?
    (1)目前Github的开源库Reachability的最新版本是3.2,苹果也出了一个Support IPV6 的Reachability的官方样例,我们比较了一下源码,跟Github上的Reachability没有什么差异。
    (2)我们通常都是通过一个0.0.0.0 (ZeroAddress)去开启网络状态监控,经过我们测试,在iOS9以上的系统上IPV4和IPV6网络环境均能够正常使用;但是在iOS8上IPV4和IPV6相互切换的时候无法监控到网络状态的变化,可能是因为苹果在iOS8上还并没有对IPV6进行相关支持相关。(但是这仍然满足苹果要求在最新系统版本上支持IPV6的网络)。
    (3)当大家都在要求Reachability添加对于IPV6的支持,其实苹果在iOS9以上对Zero Address进行了特别处理,官方发言是这样的:


    reachabilityForInternetConnection: This monitors the address 0.0.0.0,
    which reachability treats as a special token that causes it to actually
    monitor the general routing status of the device, both IPv4 and IPv6.


    + (instancetype)reachabilityForInternetConnection {
        struct sockaddr_in zeroAddress;
        bzero(&zeroAddress, sizeof(zeroAddress));
        zeroAddress.sin_len = sizeof(zeroAddress);
        zeroAddress.sin_family = AF_INET;
        return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
    }
    
    

    综上所述,Reachability不需要做任何修改,在iOS9上就可以支持IPV6和IPV4,但是在iOS9以下会存在bug,但是苹果审核并不关心。

    四、底层的socket API如何同时支持IPV4和IPV6?

    由于在应用中使用了网络诊断的组件,大量使用了底层的 socket API,所以对于IPV6支持,这块是个重头戏。如果你的应用中使用了长连接,其必然会使用底层socket API,这一块也是需要支持IPV6的。 对于Socket如何同时支持IPV4和IPV6,可以参考谷歌的开源库CocoaAsyncSocket.

    下面我针对我们的开源 网络诊断组件, 说一下是如何同时支持IPV4和IPV6的。
    开源地址:https://github.com/Lede-Inc/LDNetDiagnoService_IOS.git
    这个网络诊断组件的主要功能如下:

    • 本地网络环境的监测(本机IP+本地网关+本地DNS+域名解析);
    • 通过TCP Connect监测到域名的连通性;
    • 通过Ping 监测到目标主机的连通耗时;
    • 通过traceRoute监测设备到目标主机中间每一个路由器节点的ICMP耗时;

    4.1 IP地址从二进制到符号的转化

    之前我们都是通过inet_ntoa()进行二进制到符号,这个API只能转化IPV4地址。而inet_ntop()能够兼容转化IPV4和IPV6地址。 写了一个公用的in6_addr的转化方法如下:

    //for IPV6
    +(NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr{
        NSString *address = nil;
        
        char dstStr[INET6_ADDRSTRLEN];
        char srcStr[INET6_ADDRSTRLEN];
        memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr));
        if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){
            address = [NSString stringWithUTF8String:dstStr];
        }
        
        return address;
    }
    
    //for IPV4
    +(NSString *)formatIPV4Address:(struct in_addr)ipv4Addr{
        NSString *address = nil;
        
        char dstStr[INET_ADDRSTRLEN];
        char srcStr[INET_ADDRSTRLEN];
        memcpy(srcStr, &ipv4Addr, sizeof(struct in_addr));
        if(inet_ntop(AF_INET, srcStr, dstStr, INET_ADDRSTRLEN) != NULL){
            address = [NSString stringWithUTF8String:dstStr];
        }
        
        return address;
    }
    

    4.2 本机IP获取支持IPV6

    相当于我们在终端中输入ifconfig命令获取字符串,然后对ifconfig结果字符串进行解析,获取其中en0(Wifi)、pdp_ip0(移动网络)的ip地址。

    注意:
    (1)在模拟器和真机上都会出现以FE80开头的IPV6单播地址影响我们判断,所以在这里进行特殊的处理(当第一次遇到不是单播地址的IP地址即为本机IP地址)。
    (2)在IPV6环境下,真机测试的时候,第一个出现的是一个IPV4地址,所以在IPV4条件下第一次遇到单播地址不退出。

    + (NSString *)deviceIPAdress
    {
            while (temp_addr != NULL) {
                NSLog(@"ifa_name===%@",[NSString stringWithUTF8String:temp_addr->ifa_name]);
                // Check if interface is en0 which is the wifi connection on the iPhone
                if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"] || [[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"])
                {
                    //如果是IPV4地址,直接转化
                    if (temp_addr->ifa_addr->sa_family == AF_INET){
                        // Get NSString from C String
                       address = [self formatIPV4Address:((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr];
                    }
                    
                    //如果是IPV6地址
                    else if (temp_addr->ifa_addr->sa_family == AF_INET6){
                        address = [self formatIPV6Address:((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr];
                        if (address && ![address isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"]) break;
                    }
                }
    
                temp_addr = temp_addr->ifa_next;
            }
        }
    }
    

    4.3 设备网关地址获取获取支持IPV6

    其实是在IPV4获取网关地址的源码的基础上进行了修改,初开把AF_INET->AF_INET6, sockaddr -> sockaddr_in6之外,还需要注意如下修改,就是拷贝的地址字节数。去掉了ROUNDUP的处理。 (解析出来的地址老是少了4个字节,结果是偏移量搞错了,纠结了半天),具体参考源码库。

       /* net.route.0.inet.flags.gateway */
        int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
    
        if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) {
             address = @"192.168.0.1";
        }
    
        ....
    
        //for IPV4
        for (i = 0; i < RTAX_MAX; i++) {
                    if (rt->rtm_addrs & (1 << i)) {
                        sa_tab[i] = sa;
                        sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
                    } else {
                        sa_tab[i] = NULL;
                    }
                }
    
      //for IPV6
         for (i = 0; i < RTAX_MAX; i++) {
                    if (rt->rtm_addrs & (1 << i)) {
                        sa_tab[i] = sa;
                        sa = (struct sockaddr_in6 *)((char *)sa + sa->sin6_len);
                    } else {
                        sa_tab[i] = NULL;
                    }
                }
    
    

    4.4 设备DNS地址获取支持IPV6

    IPV4时只需要通过res_ninit进行初始化就可以获取,但是在IPV6环境下需要通过res_getservers()接口才能获取。

    +(NSArray *)outPutDNSServers{
        res_state res = malloc(sizeof(struct __res_state));
        int result = res_ninit(res);
        
        NSMutableArray *servers = [[NSMutableArray alloc] init];
        if (result == 0) {
            union res_9_sockaddr_union *addr_union = malloc(res->nscount * sizeof(union res_9_sockaddr_union));
            res_getservers(res, addr_union, res->nscount);
            
            for (int i = 0; i < res->nscount; i++) {
                if (addr_union[i].sin.sin_family == AF_INET) {
                    char ip[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN);
                    NSString *dnsIP = [NSString stringWithUTF8String:ip];
                    [servers addObject:dnsIP];
                    NSLog(@"IPv4 DNS IP: %@", dnsIP);
                } else if (addr_union[i].sin6.sin6_family == AF_INET6) {
                    char ip[INET6_ADDRSTRLEN];
                    inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN);
                    NSString *dnsIP = [NSString stringWithUTF8String:ip];
                    [servers addObject:dnsIP];
                    NSLog(@"IPv6 DNS IP: %@", dnsIP);
                } else {
                    NSLog(@"Undefined family.");
                }
            }
        }
        res_nclose(res);
        free(res);
        
        return [NSArray arrayWithArray:servers];
    }
    

    4.4 域名DNS地址获取支持IPV6

    在IPV4网络下我们通过gethostname获取,而在IPV6环境下,通过新的gethostbyname2函数获取。

    //ipv4
    phot = gethostbyname(hostN);
    
    //ipv6
     phot = gethostbyname2(hostN, AF_INET6);
    

    4.5 ping方案支持IPV6

    Apple的官方提供了最新的支持IPV6的ping方案,参考地址如下:
    https://developer.apple.com/library/mac/samplecode/SimplePing/Introduction/Intro.html

    只是需要注意的是:
    (1)返回的packet去掉了IPHeader部分,IPV6的header部分也不返回TTL(Time to Live)字段;
    (2)IPV6的ICMP报文不进行checkSum的处理;

    4.6 traceRoute方案支持IPV6

    其实是通过创建socket套接字模拟ICMP报文的发送,以计算耗时;
    两个关键的地方需要注意:
    (1)IPV6中去掉IP_TTL字段,改用跳数IPV6_UNICAST_HOPS来表示;
    (2)sendto方法可以兼容支持IPV4和IPV6,但是需要最后一个参数,制定目标IP地址的大小;因为前一个参数只是指明了IP地址的开始地址。千万不要用统一的sizeof(struct sockaddr), 因为sockaddr_in 和 sockaddr都是16个字节,两者可以通用,但是sockaddr_in6的数据结构是28个字节,如果不显式指定,sendto方法就会一直返回-1,erroNo报22 Invalid argument的错误。

    关键代码如下:(完整代码参考开源组件)

    //构造通用的IP地址结构stuck sockaddr
    
     NSString *ipAddr0 = [serverDNSs objectAtIndex:0];
        //设置server主机的套接口地址
        NSData *addrData = nil;
        BOOL isIPV6 = NO;
        if ([ipAddr0 rangeOfString:@":"].location == NSNotFound) {
            isIPV6 = NO;
            struct sockaddr_in nativeAddr4;
            memset(&nativeAddr4, 0, sizeof(nativeAddr4));
            nativeAddr4.sin_len = sizeof(nativeAddr4);
            nativeAddr4.sin_family = AF_INET;
            nativeAddr4.sin_port = htons(udpPort);
            inet_pton(AF_INET, ipAddr0.UTF8String, &nativeAddr4.sin_addr.s_addr);
            addrData = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
        } else {
            isIPV6 = YES;
            struct sockaddr_in6 nativeAddr6;
            memset(&nativeAddr6, 0, sizeof(nativeAddr6));
            nativeAddr6.sin6_len = sizeof(nativeAddr6);
            nativeAddr6.sin6_family = AF_INET6;
            nativeAddr6.sin6_port = htons(udpPort);
            inet_pton(AF_INET6, ipAddr0.UTF8String, &nativeAddr6.sin6_addr);
            addrData = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
        }
        
        struct sockaddr *destination;
        destination = (struct sockaddr *)[addrData bytes];
    
    //创建socket
    if ((recv_sock = socket(destination->sa_family, SOCK_DGRAM, isIPV6?IPPROTO_ICMPV6:IPPROTO_ICMP)) < 0)
    if ((send_sock = socket(destination->sa_family, SOCK_DGRAM, 0)) < 0)
    
    //设置sender 套接字的ttl
    if ((isIPV6? 
    setsockopt(send_sock,IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)):
    setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) < 0)
    
    //发送成功返回值等于发送消息的长度
    ssize_t sentLen = sendto(send_sock, cmsg, sizeof(cmsg), 0, 
    (struct sockaddr *)destination, 
    isIPV6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in));
    
    

    最近团队缺人,插播一条小招聘广告,有换工作的同行请把简历砸给我!

    简历发送邮箱:huipang@corp.netease.com

    【网易-社招-北京】iOS高级开发工程师职位

    工作地点:北京
    工作职责:
    1.负责研发网易电商移动端iOS应用
    2.负责性能调优等重点难点技术攻坚;
    3.及时跟踪了解移动领域新技术,进行技术方案更新;

    任职资格:
    1.全国重点高校本科及以上学历,1年以上的iOS开发经验
    2.数据结构、算法等基础知识扎实,有良好的架构设计能力;
    3.具备良好的分析解决问题能力,有技术难题攻关经验,善于主动推进项目进展并达成项目目标;
    4.熟练掌握Objective-C/Swift语言,熟练掌握iOS开发技术,包括但不限于Foundation、UIKit、内存管理、多线程、Runtime、网络编程等,熟练使用Xcode及相关调试工具;
    5.有较强责任感和严谨工作作风,有良好的团队合作和协调能力;
    6.热爱移动互联网,对新事物敏感,喜欢探索,有较强的创新意识。

    岗位福利:14薪+季度奖+年终奖+年度旅游等

    简历发送邮箱:huipang@corp.netease.com

    相关文章

      网友评论

      • 那位小姐:现在的ipv6 是不是强制了 我几次审核都是因为ipv6 被打回来了 需要怎么处理 服务器说他已经处理了 但是没有处理DNS ios11链接可以有网 但是我的10连接就没有网
      • 3e8eb14bdf82:苹果的审核机制是,当应用崩溃或异常,他会先测你是不是支持ipv6,我们公司所有的接口都不支持ipv6,然后就告诉你可能是ipv6引起的
        3e8eb14bdf82:苹果这种做法很不负责任,容易误导苦逼的程序员,去傻乎乎搭建ipv6测试环境,也测不出个所以然来。
      • HelloYeah:楼主,App在移动4g下,加载网页.didFinshLoad回调速度很慢(1-2分钟),联通网络没问题.这个bug是由于ipv6的问题导致的吗
      • 梁森的简书:dig +nocmd + nostats 你的域名 AAAA查看服务器是否支持IPV6
      • coder_那一抹刚吹过的风:有个事请求一下,我想知道IPv4的服务器会按照什么规则合成这个IPv6地址。这应该不能正确寻址吧
      • 标记0_9:混合开发app,一直审核不通过原因是ipv6连接不上。这个情况要怎么处理?
        已经配置了域名ipv6隧道,服务器用的阿里云本身就已经有ipv6隧道。
      • adcf54fccc2b:还是在淘宝直接找了就过了,折腾我一个月,差点饭碗都丢了。悲剧,看在商家给我帮大忙的份上,给个链接:https://item.taobao.com/item.htm?spm=a1z09.8149145.0.0.vx1Dqx&id=551906449495&_u=7nvvofbb6c
      • 吴钧泽:请问 怎么样让阿里云的服务器支持IPv6呢?
      • 三线小奋青:楼主,你好,我用的AFNetWorking 请求的数据,是不是监测到ipv6的时候就判断用域名来链接就可以了,具体的应该如何去判断呢?求助:pray:
        三线小奋青:@betterton 我就直接用域名去请求网络,然后af用最新的版本就通过了
        betterton:您好 知道如何判断了吗?
      • Joy___:好厉害:hushed:
      • 哈哈大笑呼呼呼呼:楼主你好 formatIPV6Address你的这段代码怎么来的求解释下着急 或者没有demo之类的谢谢了
      • 肆意二货:我提交项目,说是不支持ipv6被拒,然后我的项目用的是afn请求的网络,服务器说他们那边是支持ipv6的,现在很无语,不知道怎么解决这个问题了。可以帮忙一下么?
        肆意二货:@CoderZb 后面我们有自己搭建ipv6的环境,然后后面就审核通过了。我们设置了图片。如果你试了多次,还是不行,你可以试着录制一个视频。
        CoderZb:请问一下,我这边也是afn,服务器那边也是没有问题,请问是怎么解决的呢,麻烦@一下我哦
      • 398b2cefc381:好文,点个大赞啊,我们先按您的建议试一下,感谢,另外好文我这边转载了一下。留了原文链接。http://www.jxbh.cn/article/1835.html 如有冒昧,请联系删除。谢谢。
      • 李某lkb:我按照上面的方法搭建ipv6,什么应用都不行,求解
      • TERENCEYAO:在这个 IPv6 环境底下,会有一个 IPv6 DNS。(废话)
        这个 IPv6 DNS 神奇的地方是:假设伺服终端有 IPv4-Only 域名,当你透过 DNS 查询 (getaddrinfo) 时,它会自动配发一个 IPv6 地址,虽然你仍可以捞到 IPv4 地址。
        但这意味着你要透过 AF_INET6 家族,对它所配发的 IPv6 做资料传送,NAT64 这时就会将封包转发到 IPv4 去。
        所以现在最大的问题是:假设在自己的自订协议里,IP 描述不是使用域名的状况,如 NAT 穿越应用,也就是遇到 NAT64 对 IPv4 时,可能会有问题,单单将 IPv4 转成 IPv6 格式去传送或连线似乎不一定有效。
        TERENCEYAO:@TERENCEYAO
        更正:经过刚刚测试,IPv4 转成 IPv6 格式 可行,
        格式要采用 ::ffff:xxx.xxx.xxx.xxx
      • 863c73f31933:你好,楼主,由于我这边iOS真机设备没有那么多,模拟器能模拟访问ipv6不,
      • 七堇年华cc:好文,大神果断懂得很多,自惭形秽啊!~
      • f1bd5906b5f5:服务器 需要支持ipv6吗
      • 我爱月光下的承诺:楼主,请问RESTKit支持ipv6吗?小菜一个。
      • 跑调的安眠曲:iOS 10获取网关有问题,iOS9直接返回ipV4的地址,iOS10因为获取到ipV6的地址,所以它返回的是ipV6的地址
      • 旅行的光:想问一下,iOS是否能够支持socket同时通过Wi-Fi和4g连接不同的端口?谢谢啦
      • 打盹小猪:因为这个昨天被拒了
      • 小霍同学:我想问一下,服务器端需要做什么适配吗
      • areckkimo:你好
        我的APP送了5-6都被reject
        說是ipv6環境下測試失敗
        但是已經在mac搭建的ipv6下測試都沒問題
        像ip改成doman也確認過
        另外也檢查過code沒有ipv4 apis
        也將afnetworking升級至3.0.4
        到底是那裡沒改到
        請大家幫幫忙
        小弟快被apple搞瘋了
        怪兽怕妈妈:@areckkimo 请问你的问题解决了么
      • MooneyWang:3.2 Cocoa的URL Loading System从iOS哪个版本开始支持IPV6?关于这个问题,不知道楼主是否已有进展?
      • Glenn_h:请问服务器是不是必须得支持IPV6?
      • 志城:GCDAsyncSocket 关于这个的支持该如何入手呢?
      • toplee:不太会看啊,怎么看有没有成功,楼主可以加一下qq吗?1713521474
        toplee:@philon 加了啊,没反应。。。。。。
        我用了域名访问 但是在ipv6上还是不能访问啊
        淡淡如水舟:@toplee 加群,574410254
      • Jin丶hy:楼主 你好 我用电脑模拟ipv6网络 测试app 程序以运行就crash 断在[MSFTcpConnect logDNSResult:]:这个地方 请问楼主有什么思路吗
        淡淡如水舟:@Jin丶hy 加群 574410254
      • toplee:我搭建了ipv6的环境,但是手机一直连不上WiFi啊,WiFi的详细情况中IP地址有、子网掩码也有,但是dns没有,一直连不上,有没有大神遇到过啊,大神们怎么解决的啊
        淡淡如水舟:@toplee 你在你搭建的IPv6环境的那台机器的终端用ifconfig 命令查询一下是否为IPv6 的地址,确认一下环境有没有搭建成功,如果没有问题,换台机器看看!
      • toplee:你好,我搭建了ipv6的环境,但是手机连接wifi的时候一直连不上,手机系统也是最新的了
      • maotw:存不存在 服务端吧ipv6 访问禁止了,造成ipv6 -only 失败问题?
        淡淡如水舟:@maotw 有可能,你ping一下服务器端的域名
      • 红鲤鱼蓝鲤鱼与驴:6.4号提交一版还好好的,前两天提交一版就被拒了,跟审核人员沟通说在ipv4和ipv6下都不能登录,可是我在本地测试都能登录啊,楼主能不能帮忙分析一下可能是哪的问题。。。
      • ForgetThatNight:公司发了一个通知:由于苹果要求在6月之前全部应用兼容IPV6,所以请大家更新sdk至5.2.1版本避免提交APPStore审核被拒,谢谢。。。这个通知说的SDK是什么SDK呀?找到中午了,还没找到
        ForgetThatNight:好的,我去问问3Q
        淡淡如水舟:应该是你们内部的网络基础库什么的吧!
      • Highgray:楼主, 我前两天提交了个app, 获取数据是直接通过ip地址请求的. 然后今天接到被拒邮件, app其实仅仅是一个演示项目, 除了网络请求, 没有其他特殊的东西在里面了. 我大概查了一下资料, 是不是只要把我请求的url中ip的部分改成域名就可以了? 谢谢楼主
      • 春风十里p:楼主 你好 我用电脑模拟ipv6网络 测试app 程序以运行就crash 断在[MSFTcpConnect logDNSResult:]:这个地方 请问楼主有什么思路吗
        Jin丶hy:@春风十里p 加群 574410254 楼主开了个群,或者加你qq 一起研究下。
        Jin丶hy:@春风十里p 同问啊。我也是这个问题。可是找这个类都不知道属于哪里的。
      • 攻城狮丶:楼主 问个问题微信支付的IPV6适配不行啊怎么弄 一直提示spbill_create_ip 参数长度不正确 就是因为获取了ipv6的地址 不然就是正常的 已经替换过了微信SDK
      • 95f80190bca9:用域名比用ip好,因为ipv6-only网络可以通过DNS64换回一个ipv6的地址,这样通过这个ipv6地址,既可以访问到ipv4的网址也可以访问到ipv6的网址,然后主要是要把传输库改成能支持ipv6就可以了,但现在问题又来了,怎样判断当前网络是 ipv4还是ipv6?
        我没喝酒啊:@95f80190bca9 确定是ip的问题吗
      • NorahWu:楼主,ipv6的客户端和ipv4的服务器连接, xxx.xxx.xxx.xxx类型的地址要怎样处理才能连接上呢???

        NorahWu:@philon 我尝试用了ipv4转换过来的ipv6的地址去链接 但是返回错误说 主机不可达, 是不是服务器还要配置一些什么???
        淡淡如水舟:@NorahWu 需要知道服务器端的ipv6地址,在v6环境下,用服务器的域名可以解析出一个6的地址,用这个地址建立连接就可以了!!至于服务器端域名配支持IPv6的解析我不是很清楚,咨询一下你们公司的运维吧!
      • 198e9db11366:作为一个半路出家点新手,真的被难到了,几天了,看了很多篇文章都是一头雾水,终于找到了这篇文章的出处,楼主能帮帮忙吗,向服务器发送的连接请求,是用的ip地址链接的,服务器是有ipv4和ipv6两个地址的 ,应该怎么做才能通过审核,尽量直白一点的语言,因为是自学的计算机基础有点擦,时间也不长,很多术语都看不太懂。。。。
        198e9db11366:@philon 还有,云主机的fqdn是怎么查看,我在其他地方看到的查看fqdn的方法,但是只能找到计算机全名 "iZ946lf5agaZ"
        198e9db11366:@philon 我看了您上面跟别人的对话,是只要设定iOS9.0以上的,就能通过审核吗
        淡淡如水舟:@学渣王 在ios9以上如果用ipv4地址通过nsurlconnection或者nsurlsession 都可以请求成功!所以你啥都不用做就可以了!
      • b11ddc0aed07:请问CocoaAsyncSocket支持ipv6么?需要修改什么吗?
      • 3625cdff19be:不支持的已经开始crash被拒绝了
      • cebe0bfbc442:你好,照你这么说GCDAsyncSocket这个库是支持IPv6的,但是不知道为什么,在ipv4环境下我可以正常使用,但是在ipv6的环境下一直连接不上(报无网络,也就是Domain=NSPOSIXErrorDomain Code = 51 "Network is unreachable")。是不是还要注意什么呢?
        cebe0bfbc442:@b11ddc0aed07 IPv4PreferredOverIPv6默认值为YES,意思大致是:如果为YES则代表DNS lookup返回结果两者都有的话就会选择IPV4。所以如果不设置为NO的话,他就会走IPV4的网络,不会走IPV6了。所以会出现Network is unreachable。(当然还有个IPv6Enabled的属性注意,一般默认已经开启了)
        b11ddc0aed07:请问下为啥要设置这个IPv4PreferredOverIPv6 这个的作用是什么?
        cebe0bfbc442:已经解决了,原来还要单独设置该对象的IPv4PreferredOverIPv6 = NO;就可以在IPv6的环境下使用了
      • 买了否冷_:看完有点头大,,请问一般应用应该做哪些处理 或者改添加那些代码呢 封装网络继承自2.*版本AFN里的AFHTTPSessionManager 谢谢!
        买了否冷_:@philon 谢谢 :smile:
        淡淡如水舟:@偷偷学很多东西 继承sessionManager不需要修改!
      • 5d799bc8380f:您好,SDWebImage说他自己不支持IPv6,但是我看代码他的请求用的是NSURLConnection。为什么SDWebImage不支持IPv6呢
      • 跑调的安眠曲:4.3 设备网关地址获取获取支持IPV6 这个好像不完整吧?
      • stillwalking:在微信上看过此文,所以,你就是原作者吗?
      • Zeke权:i你好,我们的项目使用AsyncUdpSocket发送广播,之前没接触过,现在要适配ipv6,无从下手了,能指点一二吗
      • f3969479e601:我们用了xmppframework框架,然后看里面就是CocoaAsyncSocket进行socket 连接,但是在ipv6_only的环境下就是连接不上xmpp。不过路由器那边不支持ipv6,是要换设备嘛?? :sob: ,头大啊,楼主。
        3625cdff19be:为了推动ipv6,点名说了路由设备要支持,不支持就要被替换掉
        淡淡如水舟:@织meng者 xmppframework框架我没有用过,不过你检查一下里面的socket是如何建立连接的,如果是通过域名建立连接,需要看看通过域名解析出来的地址是否为IPV6地址,如果是通过ipv4地址建立的连接,应该需要换成用IPV6的地址;
      • eb410aa21d76:好好好
      • 红色小星:太及时了
      • S_MG:你好,官方文档中说了不要使用IP地址,但是后面又说9.2系统之后可以使用getaddrinfo合成IPv6地址。9.0系统后是高级别的网络框架是自动合成IPv6地址的,而且测试发现9.0系统之后使用IP地址请求是可以在IPv6正常使用的(8.4的系统不能正常请求)。那我不替换IP地址为域名也可以吗?
        淡淡如水舟:@S_MG 看到你的评论之后,我在我们项目用IPV4地址进行了测试(模拟器);在iOS9及以上确实可以访问,在iOS8.4及以下不能访问;苹果也给出了解释,说NSURLSession和CFNetworking在IPV6 NAT64环境下能够将IPV4地址自动合成一个IPV6地址,所以可以访问;
        已经将这条信息更新到文章中了,感谢指点;
      • d611ec22c786:AFN里reachability ipv6 的适配,我在手动搭建的ipv6网络换讲下,使用ios9.2设备 还是走的ipv4的逻辑,什么条件会走ipv6的逻辑?+ (instancetype)manager
        {
        #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
        struct sockaddr_in6 address;
        bzero(&address, sizeof(address));
        address.sin6_len = sizeof(address);
        address.sin6_family = AF_INET6;
        #else
        struct sockaddr_in address;
        bzero(&address, sizeof(address));
        address.sin_len = sizeof(address);
        address.sin_family = AF_INET;
        #endif
        return [self managerForAddress:&address];
        }
        另外,针对你的开源代码[_netConnect runWithHostAddress:[_hostAddress objectAtIndex:i] port:80];
        我把ip换成公司ip,使用自己搭建的ipv6网络 连接超时,请问是不是是配上还是有点问题?谢谢
        淡淡如水舟:@cctao89 第二个问题:开源代码中netConnect,先通过getDNSAddress拿到域名解析出来的DNS地址,如果在IPV4网络返回IPV4地址,如果是IPV6网络下,只返回IPV6地址; Demo中你输入你们api接口的域名就可以检测;
        淡淡如水舟:@cctao89 其实这个修改我们觉得是没有什么用,苹果的官方reachability 支持ipv6直邮下面else的逻辑,是因为在苹果系统将0.0.0.0地址当成了一个特殊标记,都可以支持;文章有提到;
        淡淡如水舟:@cctao89 第一个问题:AF里面的修改是一个静态宏,意思是说你app的最小系统支持版本是9.0及以上的时候会走if里面的逻辑;如果小于9.0都会走else的逻辑;
      • Jianhong_z:你好,
        相当于我们在终端中输入ifconfig命令获取字符串,然后对ifconfig结果字符串进行解析,获取其中en0(模拟器)、pdp_ip0(真机)的ip地址。

        这里的en0 好像是Wi-Fi,pdp_ip0 是移动网络
        淡淡如水舟:@Jianhong_z 确实是的,我修改一下,谢谢指点;
      • 3aef6558f4b7:楼主,您好! 我最近在适配IPV6,目前服务器的所在机房不能提供IPV6,我们项目是直接使用的 socket()函数创建的 ,现在能直接使用IPV6的客户端去访问IPV4的服务器吗?
        97030f7d00c7:@低头式高调 请问问题解决了吗?
        3aef6558f4b7:@philon 现在国内好多机房都不能提供IPV6的IP地址,这是要坑死人的节奏啊
        淡淡如水舟:@低头式高调 自己用socket创建的,需要服务器端能够给一个IPV6地址,不然你无法你无法建立socket通信吧;可以看看开源代码里面的traceRoute部分代码,跟你这个差不多;
      • 闭眼_聆听世界:上次我用mac系统偏好-共享-互联网共享(创建 NAT64 网络), 用老项目, iPhone 6s+ 不能上网啊. 系统铁定是9.0+的
        闭眼_聆听世界:@philon 谢谢, 你的意思就是封装好的请求就得考虑到这些了。 公司好像么有这么高的人, 可以不可以列个新手封装的顺序,就是考虑的方面:smile:
        淡淡如水舟:@闭眼_聆听世界 得具体看你们项目的网络请求那块:(1)看是不是用了cocoa url loading那一套API;(2)看有没有自己做DNS解析;(3)是不是自己用了长连接或者socket之类的去做网络请求;
      • Wells_Y:开始ping...
        2016-05-25 14:18:12.716 LDNetDiagnoServiceDemo[2204:1181085] ping: 开放服务器 ...
        2016-05-25 14:18:12.727 LDNetDiagnoServiceDemo[2204:1181085] #1 try create failed: nodename nor servname provided, or not known


        这是为啥ping不成功?
        淡淡如水舟:@惊鸿一瞥_ 苹果出的支持IPV6的SimplePing方案把IPHeader这部分去掉了,所以在最新的代码中我就没有取这个值了;为什么去掉是因为IPV6的header和IPV4的header不一样,没法统一处理;
        Wells_Y:@philon 有办法获取到ttl或者hops吗? 从IPV4Header中解出来的timeToLive都是固定32.。。。
        淡淡如水舟:@惊鸿一瞥_ 开源代码中开放服务器的IP我没有写,这个是我们自己内部用的;你可以填上你们的域名或者IP就行;
      • hxbtec:卤煮啊,我们项目有一个局域网文件传输功能,然后以前都是直接使用的ipv4 socket,现在要兼容ipv6-only的话,我怎么样才能知道当前网络是否是ipv6-only环境,然后去创建对应的socket呢?
        hxbtec:@philon 卤煮,我看了你的代码,你那个也采用是优先使用ipv6方案吧?但还是没有办法判断是不是ipv6-only的网络环境吧?在我试了在ipv6-only也就是apple说的NAT64环境下也是会返回ipv4的地址的,这种情况下我要怎么才能确定当前是NAT64环境呢? :sob:
        hxbtec:@philon 好的,我看看,谢谢。
        淡淡如水舟:@hxbtec 你可以获取当前设备的ip地址来判断,对于服务器端的目标地址我是先通过域名通过DNS解析返回一个地址数组,在IPV4环境下不会返回IPV6的地址,在IPV6环境下会返回IPV4的地址;(这段逻辑可以参考我分享的那个网络诊断组件)看是否返回IPV6地址判断网络环境;
      • nicodeng:楼主,请问afnetworking支持ipv6吗?
        非夜:@philon 你确定你测过?ios8.x?你逗我呢,iOS8、7根本支持不了,我测了一上午了,就AFN
        淡淡如水舟:@nicodeng AFNetworking的请求不能是通过IPv4地址,只能通过域名请求直接;有些应用为了省掉DNS解析时间,baseURL直接传的IPv4地址,这样是不支持的;
        淡淡如水舟:@nicodeng AFNetworking都是在NSURLConnection和NSURLSession基础上的封装,是支持的,AF里面的Reachability也没有问题;(我说的支持都是指在IOS8和IOS9上,自己测试过,IOS7我没有测试过)
      • 吸血鬼de晚餐:最近遇到了这个事情
      • 赵三思:请教下楼主:
        "给予的答复是只需要在苹果最新的系统上保证IPV6的兼容性即可。"
        这个信息可信吗.是否有苹果官方邮件截图?
        或者咨询这类问题,应该向苹果官方的哪个邮箱发邮件呢?
        淡淡如水舟:@赵三思 我们公司内部有个iOS技术交流群,刚刚跟他确认了一下,他确实是咨询的苹果审核那边的人;而且说的最新系统是指的iOS9.3
      • 6651706c3b6d:请问ASI 还能用吗
        Yancy_90:@明子55 谢谢!
        6651706c3b6d:@philon 抱歉,因为无法搭建ipv6的环境无法实测,不过经过其他求证ASI没有问题,前天提交的上线版本也已经通过
        淡淡如水舟:@明子55 ASI我们没有用,所以没有去调研,不能给出肯定的答案,不过ASI也是在CFNetowork的基础上上的封装,按理说在IOS9上也应该能用,你可以去测试一下,还望给予回复!!
      • 古斯比德:好文,收藏!
      • MrPeak:楼主,请教个问题。
        我们服务器ip地址都是ipv4的,连接socket时都是直接写ip的,发现一个奇怪的问题,除了80,443端口之外,其他端口ipv6环境下所创建的socket都无法连接成功,这是什么原因呢?
        晒着的鱼_9524:@愚公编程
        在使用 UDP(CocoaAsyncSocket) 发现getaddrinfo 合成ipv6的时候会把端口设成0,需要重新设置一下端口。
        淡淡如水舟:@愚公编程 你参考一下CocoaAsyncSocket这个库吧,连接是https://github.com/robbiehanson/CocoaAsyncSocket,看你用的socket API是苹果封装的(CFSocketRef)还是直接用了linux的底层的(socket()函数创建的),如果用的是苹果封装的API,我猜测是针对80,443这些公有端口合成了一个IPV6地址,可以创建,对于私有的端口没有合成~~
      • f596b6e6e526:楼主,代码里用到了ntoa 这个在ipv6-only这个函数是不允许用的,需要用ntop函数代替
        淡淡如水舟:@jzhyng 我已经改过来了,还是保险一点,万一苹果监测这些API拒绝就悲剧了;
        f596b6e6e526:@philon 应该是谢谢楼主,解决了我很多问题
        淡淡如水舟:@jzhyng 感觉苹果没有说不让用吧,原话是这样说的:Check Source Code for IPv6 DNS64/NAT64 Incompatibilities, Check for and eliminate IPv4-specific APIs, 代码中用到的的ntoa函数只是支持处理IPV4的情况,IPV6的情况用了ntop函数,不过我还是修改一下吧,谢谢指点~~
      • 齐刘海姑娘:哈喽~您的文章已收录专题【我不是程序猿,请叫我攻城狮】http://www.jianshu.com/collection/db91065b98c6,欢迎关注投稿哦~ :kissing_heart: :heart: :heart: :smile:
        李盛民:楼主都没同意,你就收录了。
        Sunny_Jiang:楼主都没同意 你就收录了~
        zyg:@齐刘海姑娘在DevStore :sweat: 楼主都没同意 你就收录了~
      • vvvei:一般的应用,服务端都没有ipv6吧?为了通过审核,在ipv6环境下直接通过域名连接就可以。
        普及ipv6在国内不知道多久呢……
        toplee:@vvvei 用了域名访问 但是在ipv6上还是不能访问啊
        8d345acefd23:@vvvei 好像没用啊··试过了啊

        孤居引:@vvvei 你说的域名连接是SCNetworkReachabilityCreateWithName这种吗?

      本文标题:iOS应用支持IPV6,就那点事儿

      本文链接:https://www.haomeiwen.com/subject/plzarttx.html