cocos2d ipv6

2016年6月1日,苹果出台新政策,要求所有提交Apple Store渠道的包必须要支持IPv6。这昂无疑让很多人心头一凉。 
果然在这几天很多公司的产品都被打回来了。我们公司也不例外,提交了几个包,只有一款侥幸逃过一劫,其它全部被打回。 
碰到这种问题,第一时间就去调查了下,首先肯定是去构建一个ipv6网络测试。面临着一大堆的问题,这个是客户端还是服务端的问题?如果是服务端的问题,怎么处理,服务端需要更改什么内容?如果是客户端的问题又怎么办呢?…… 
慌归慌,事情还是要去处理,首先去百度科普下苹果的这条新规的规则,然后再去熟悉下什么是ipv6(尴尬脸~)。这个就不赘述了,自行度娘。

怎么搭建ipv6的网络? 
这个估计网上搜索一大堆,简单描述下。苹果机器是可以分享一个ipv6网络热点的。首先找一台苹果机器,连上网线(必须是以太网),然后再设置界面按option键,单机分享,就可以在互联网共享看到,创建NAT64网络的checkbox,我们勾选上,然后分享热点就可以了。一顿测试,发现很多游戏不能正常玩下去。

服务端需要修改吗? 
服务端是否要修改,这个问题估计是大家比较关注的问题,因为如果服务端需要修改,那就麻烦了(可能其实并不麻烦~ 欠揍脸)。正好公司有oc写的客户端,拿了一个包在ipv6环境下测试,是正常的(因为实用了CFNETWork,苹果提供的兼容ipv6的网络库)。所以看得出来,服务端基本不需要修改。

需要在域名绑定的时候修改一个ipv6地址吗? 

一开始我也纠结了下这个问题,是不是需要去绑定一个ipv6的地址。后来用oc写的客户端可以连接正常,说明基本没问题,不需要特别操作。那么基本得出结论,只要在客户端修改即可。


怎么改? 
cocos2d-x 第一时间就更新了自身的curl和web socket。 http://forum.cocos.com/t/ipv6-only/36895

 根据苹果官网提出的修改策略,我们的http、socket都需要支持。所以我们可以更新cocos团队提供的patch。简单解决http的问题。
 现在最麻烦的事去修改socket,因为我们使用了BSDSocket的封装。网上并不难查到相关的资料,虽然基本都是如出一辙。

修改Socket 
IPv4是“.”来分割的,但是IPv6是“:”来分割的。客户端如果是用苹果家族的语言开发的,我们基本不需要修改,或者是很少量的修改,因为他们本身提供的库就只支持。但是Cocos2d-x开发,我们一般会自行封装自己的Socket。一般来说是BSDSocket的使用。这时,我们就需要去做如下工作了。

一、将项目中的ip地址全部改成域名,因为IPv4的地址跟IPv6的地址不一样。另外解析域名的时候不再使用 gethostbyname函数,而是使用 getaddrinfo函数。添加一个网络判断的函数。

//判断是否IPv6网络

staticbool isIPV6Net(conststd::string domainStr = "www.baidu.com")
{
bool isIPV6Net = false;

struct addrinfo *result = nullptr, *curr;

struct sockaddr_in6 dest;
bzero(&dest, sizeof(dest));

dest.sin6_family = AF_INET6;

int ret = getaddrinfo(domainStr.c_str(), nullptr, nullptr, &result);
if (ret == 0)
{
for (curr = result; curr != nullptr; curr = curr->ai_next)
{
switch (curr->ai_family)
{
case AF_INET6:
{
isIPV6Net = true;
break;
   }
case AF_INET:

break;

default:
break;
}
}
}

freeaddrinfo(result);

return isIPV6Net;
}

二、添加域名解析函数

static std::string domainToIP(const char* pDomain)
{
if (isIPV6Net())
{
struct addrinfo hint;
memset(&hint, 0x0, sizeof(hint));
hint.ai_family = AF_INET6;
hint.ai_flags = AI_V4MAPPED;

addrinfo* answer = nullptr;
getaddrinfo(pDomain, nullptr, &hint, &answer);

if (answer != nullptr)
{
char hostname[1025] = "";
getnameinfo(answer->ai_addr, answer->ai_addrlen, hostname, 1025, nullptr, 0, 0);

char ipv6[128] = "";
memcpy(ipv6, hostname, 128);

CCLOG("domainToIP addrStr:%s", ipv6);
return ipv6;
}

freeaddrinfo(answer);
}
else
{
struct hostent* h = gethostbyname(pDomain);
if (h != NULL)
{
unsigned char* p = (unsigned char *)(h->h_addr_list)[0];
if (p != NULL)
{
char ip[16] = { 0 };
sprintf(ip, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
return ip;
}
}
}
return "";

}


、修改Socket初始化函数

m_uSocket = socket((isIPV6Net()?AF_INET6:AF_INET), SOCK_STREAM, IPPROTO_TCP);

、Socket连接函数 

Connect函数的第二个参数的获取

struct sockaddr* WWInetAddress::getSockaddr() const
{
return m_isNetWorkIpv6 ? (struct sockaddr*)&addr_v6 : (struct sockaddr*)&addr_v4;
}

三个参数获取

int WWInetAddress::getLength()
{
return m_isNetWorkIpv6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);
}

连接Socket

int nRet = ::connect(m_uSocket, m_oInetAddress.getSockaddr(), m_oInetAddress.getLength());

五、其它需要注意事项 

Socket发送接口及接收数据接口都不需要去处理,另外需要考虑的是Socket的重连,及网络切换的问题。不过这些都是流程代码,只要稍加注意即可。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值