iOS App支持IPv6-only Network中的坑和解决方案
来源:互联网 发布:java画图api 编辑:程序博客网 时间:2024/05/22 09:12
从2016年6月1号开始,苹果强制要求上架AppStore的应用支持IPv6-only network。
本文分为两部分:通过代码检查是否兼容IPv6-only网络,以及如何搭建IPv6-only网络的测试环境。旨在帮助快速检查app是否支持IPv6-only Network。可以当做Supporting IPv6 DNS64/NAT64 Networks中Ensuring IPv6 DNS64/NAT64 Compatibility一节的速成版本。
通过搭建IPv6-only网络的测试环境测试
最便捷的检查方式是:找一台Mac,共享Internet到IPv6 DNS64/NAT64网络,然后让待测试设备连接到此网络,并测试app功能是否正常。
需注意,OS X 10.11后才支持创建IPv6 DNS64/NAT64网络。如果待测试设备不是iOS或OS X或macOS设备(比如要测试Andr**d上的app是否兼容IPv6-only网络),请确保设备支持RFC6106。
用在OS X(macOS)上创建IPv6 DNS64/NAT64网络很简单,只需要:
- Mac带有两块网卡。如果是Macbook Pro with retina display或者Macbook Air,可以买一块Thunderbolt或USB转RJ45接口的网卡来解决这个问题。
打开System Preference,按住Option点击Sharing,松开Option:
勾选 Create NAT64 Network,把来自其他网卡的Internet共享给Wifi:
将测试设备连接到此Wifi,并测试App功能是否正常。
检查代码是否兼容IPv6-only网络
1. 尽量使用高级API
尽量使用以下框架实现网络请求:
- WebKit.
- Cocoa URL loading system. 比如NSURLSession, NSURLRequest, 和 NSURLConnection。
- CFNetwork.
2. 避免使用IPv4地址
- 确保在代码中不会传递点分十进制表示的IPv4地址字符串(xxx.xxx.xxx.xxx)到底层网络API:比如确保不要传递点分十进制表示的IPv4地址字符串到getaddrinfo或SCNetworkReachabilityCreateWithName。需注意前面提到的高级API则会自动转换点分十进制表示的IPv4地址字符串到IPv6,所以在使用高级API时传递点分十进制表示的IPv4地址字符串时仍然可以正常工作。虽然如此,使用高级API时也应避免直接使用点分十进制表示的IPv4地址字符串。
- 使用地址无关的API:尽量传递主机名或全称域名(FQDN)给getaddrinfo或getnameinfo。
3. 避免使用网络检查
- 如果有条件,自己创建网络连接,检查错误状态来代替Reachability(这成本有点大,苹果有点站着说话不腰疼)。
4. 不能避免使用网络检查,则正确使用Reachability API
- 不要传递0.0.0.0到SCNetworkReachabilityCreateWithAddress。这只会检查网络中是否有router,并不代表真正能连接到互联网。
- 不要传递169.254.0.0(自分配的本地地址)到SCNetworkReachabilityCreateWithAddress来检查Wi-Fi是否激活。如需检查是否连接到Wi-Fi,请使用kSCNetworkReachabilityFlagsIsWWAN。
5. 正确使用Address Containers
- 使用足够大的结构来存储IPv6地址来避免溢出,比如sockaddr_storage。
6. 检查是否使用了不兼容IPv6的API
检查是否使用过IPv4特定的API,包括但不仅限于:
1234567891011
inet_addr()inet_aton()inet_lnaof()inet_makeaddr()inet_netof()inet_network()inet_ntoa()inet_ntoa_r()bindresvport()getipv4sourcefilter()setipv4sourcefilter()
如果代码中需要检查IPv4类型,则也应一并检查IPv6类型:
7. 连接IPv4-only的服务器时,使用getaddrinfo来保证app兼容IPv6-only网络
如果app需要连接到没有域名的IPv4-only服务器,请使用getaddrinfo处理IPv4地址,好处是当app处于IPv6-only网络时,getaddrinfo会生成一个对应的IPv6地址。
下面的代码展示了如何使用getaddrinfo正确处理IP地址。内存中ipv4_or_ipv6_str存储了一个IP地址(可以是IPv4或IPv6),然后使用getaddrinfo生成了自适应IPv4/IPv6的sockaddr,然后尝试连接到此地址。
此处有一坑。苹果修改了getaddrinfo以兼容两种网络,但是NAT64下有个bug:第二个参数传port number string,生成的sockaddr的sin_port/sin6_port始终为0;unix原始版本的getaddrinfo则没有这个问题。按照官方文档做法直接在getaddrinfo设置port number string是死活连不上的,建议参考下面代码40行/46行的hack方式,在getaddrinfo后手动设置port number给sockaddr。Demo可以点此下载:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
#include <sys/socket.h>#include <netdb.h>#include <arpa/inet.h>#include <err.h> struct addrinfo hints, *res, *res0; int error, s; const char *cause = NULL; const char *ipv4_or_ipv6_str = "192.0.2.1";//or IPv6 address string is well NSUInteger port = 80;//port of connecting server memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_DEFAULT; error = getaddrinfo(ipv4_or_ipv6_str, NULL, &hints, &res0); if (error) { errx(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } switch(res->ai_addr->sa_family) { case AF_INET: { struct sockaddr_in *v4sa = (struct sockaddr_in *)res->ai_addr; v4sa->sin_port = htons(port); } break; case AF_INET6: { struct sockaddr_in6 *v6sa = (struct sockaddr_in6 *)res->ai_addr; v6sa->sin6_port = htons(port); } break; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; /* okay we got one */ } if (s < 0) { err(1, "%s", cause); /*NOTREACHED*/ } else { printf("connected"); } freeaddrinfo(res0);
需注意,getaddrinfo兼容自动转换至IPv6地址的特性是iOS 9.2和OS X 10.11.2以后才支持的,但是这段代码可以保证在老的操作系统上的兼容性。
Over
- iOS App支持IPv6-only Network中的坑和解决方案
- iOS APP 支持IPv6-only的注意事项及兼容性考虑
- iOS APP 支持IPv6-only的注意事项及兼容性考虑
- iOS 应用完全支持 IPv6-ONLY 网络
- iOS IPv6-only 的兼容性解决方案
- iOS App对IPv6的支持
- iOS 应用如何完全支持 IPv6-ONLY 网络?
- iOS-支持ipv6-only后,开发者应该做些什么??
- iOS-支持ipv6-only后,开发者应该做些什么
- iOS IPv6-only
- iOS的 IPv6-only
- 苹果App Store新规:6月1日后所有应用必须支持IPv6-only网络
- 解决App Store 上架 IOS 程序必须支持IPV6
- iOS 支持 IPv6
- iOS 支持 IPv6
- iOS 支持 IPv6
- iOS 支持 IPv6
- Unity 支持 IPV6 (IOS)
- 一款不错的html5网站模板案例代码下载,用于开发个人网站,兼容手机与PC
- 区块链的运行原理和发展
- 【深入浅出jQuery】源码浅析--整体架构
- iOS画板实现第二波
- se 集群的搭建
- iOS App支持IPv6-only Network中的坑和解决方案
- String 常用方法
- 【深入浅出jQuery】源码浅析--奇技淫巧
- Spring Integration概述
- POJ 1625 Censored!
- Android 版本列表
- 5小时搞定谷歌原生自动化框架UiAutomator1.0
- fatal error: module file '/Users/cylm/Library/Developer/Xcode/DerivedData/ModuleCache/35BFEUGU7C7G3/
- CNN 学习系列之 perdict 以及可视化