ios IPv6适配

一、Apple声明

6月起,所有的APP都要支持IPv6-only网络。鉴于此,做为开发人员,肯定又要行动起来,那么首先要知道 IPv6-only Networks是什么。

二、Ipv6-only Networks引申

a.With IPv4 address pool exhaustion imminent, enterprise and cellular providers are increasingly deploying IPv6 DNS64 and NAT64 networks.A DNS64/NAT64 network is an IPv6-only network that continues to provide access to IPv4 content through translation.

可以看到IPv6-only Networks是让IPv6 Client通过NAT64DNS64的转换去访问ipv4资源的一种途径。下面摘自网上的一段介绍:

NAT64是一种有状态的网络地址与协议转换技术,一般只支持通过IPv6网络侧用户发起连接访问IPv4侧网络资源。但NAT64也支持通过手工配置静态映射关系,实现IPv4网络主动发起连接访问IPv6网络。NAT64可实现TCPUDPICMP协议下的IPv6IPv4网络地址和协议转换。DNS64则主要是配合NAT64工作,主要是将DNS查询信息中的A记录(IPv4地址)合成到AAAA记录(IPv6地址)中,返回合成的AAAA记录用户给IPv6侧用户。

IPv6终端用户发出的DNS请求通过DNS64设备进行域名解析。

如果存在请求域名的IPv6 DNS记录(AAAA记录),解析结果将直接返回给IPv6终端用户,IPv6终端用户使用该地址进行访问。

如果对应域名记录不是基于IPv6而是基于IPv4DNS记录(A记录),DNS64设备使用其NAT64做前缀将A记录转换为AAAA记录并转发给IPv6终端用户,IPv6终端用户经NAT64设备进行NAT转换访问相应的IPv4服务器。

如果我们想访问IPv6IPv4网络资源,那就如下图这样:

但是网络运营网不想再提供Ipv4网络,但又不能让用户访问不到IPv4资源,为了解决这个问题,布署NAT64/DNS64去解决,这时访问网络的流程就会是:

 

对于DNS64工作流程如下图:

在获取到IPv4 mapping IPv6后,client通过NAT64去访问资源

 总而言之,appstore上的app,必须能让IPv6-only Network环境也就是IPv6iPhone能通过NAT64/DNS64去访问IPv4的网络资源。

三、改造支持IPv6

苹果推荐用比较上层的framework去做网络连接,但我们游戏一般都是用低层的socket去处理网络链接的,所以需要自己去做这个处理。

其实改动也很简单,一般主要是涉及三个地方

DNS解析,socket创建,socket连接

对于DNS解析,不可以再用只适用于IPv4gethostbyname方法去获取地址,而改用getaddrinfo方法,对此用苹果的示例代码如下:

#include <arpa/inet.h>

#include <err.h>

    uint8_t ipv4[4] = {192, 0, 2, 1};
    struct addrinfo hints, *res, *res0;
    int error, s;
    const char *cause = NULL;
    char ipv4_str_buf[INET_ADDRSTRLEN] = { 0 };
    const char *ipv4_str = inet_ntop(AF_INET, &ipv4, ipv4_str_buf, sizeof(ipv4_str_buf));

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_DEFAULT;
    error = getaddrinfo(ipv4_str, "http", &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;
        }

        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*/
    }
    freeaddrinfo(res0);

对于getaddrinfo方法,函数的参数可以都按苹果推荐的参数来,     

hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;


 这里注意一点是,通过getaddrinfo(ipv4_str, "http", &hints, &res0);这样获取到的addr是没有端口数据的,一般都需要我们手工去设置一下,如:

addr->sin_port = htons(DEFAULT_HOST_PORT);

 对于IPv4IPv6有一个比较关键的点是,用于存储地址的数据结构,一共涉及到四种:

aIPv4 : struct sockaddr_in, 16 个字节

bIPv6: struct sockaddr_in6, 28 个字节

c、通用结构体1: struct sockaddr, 16个字节

d、通用结构体2: struct sockaddr_storage,128个字节

由于像socket,connect方法都是用的sockaddr *,及地址长度做为参数,而这个struct是同IPv4的长度一致的,所以对于IPv628个字节,显然是不够用的,所以如果要用一个通用的结构来存储IPv4IPv6的地址,就得用sockaddr_storage了。

这四个结构的family字段的位置是一样的,所以对于sockaddr_storage可以通过,判断family字段来进行指针的转换。

比如对于connect ,可以这样写:

 

if (addr->ss_family == AF_INET)
{
      connect(mSocketID, addr, sizeof(socketaddr_in))

}else if (addr->ss_family == AF_INET6)
{
      connect(mSocketID, addr, sizeof(socketaddr_in6);
}

 如果不使用底层的API,也可以对于APPLE平台编译apple比较上层API,更容易处理一些。

如使用CFStreamCreatePairWithSocketToCFHost 处理tcp连接会更简单一些。

最后,苹果帮我们列出了哪些常用的已经不适用于IPv6的结构及接口:

inet_addr()
inet_aton()
inet_lnaof()
inet_makeaddr()
inet_netof()
inet_network()
inet_ntoa()
inet_ntoa_r()
bindresvport()
getipv4sourcefilter()
setipv4sourcefilter()


这些函数都不适用于IPv6

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值