前言:

苹果官方出了新的规定,要求新上架的app都必须单独支持ipv6-only的网络。

准备工作:

搭建IPV6测试环境:http://blog.csdn.net/potato512/article/details/51680203  (注意:第2步,按住 Option 键,打开 共享,才能看到NAT64选项!)

问题的提出:

在ios应用的开发中,如果项目中网络层用的是SOCKET 底层 的api。需要在工程做 兼容ipv4和ipv6网络环境的处理。

解决方案:

服务器地址配置为域名,通过解析域名的方式,得到 该域名映射的ip地址,再通过这个ip地址,去进行网络通信。

我们主要做什么?

将服务器的地址,通过域名解析函数,解析为相应网络环境的ip地址。再通过这个ip地址,去和服务器通信。

如果客户端是在ipv6网络环境下,解析服务器地址的时候,会得到一个ipv6的地址。在客户端根据这个服务器的ipv6地址,建立客户端ipv6 网络环境下的 socket 通信;

如果客户端是在ipv4网络环境下,解析服务器地址的时候,会得到一个ipv4的地址。在客户端根据这个服务器的ipv4地址,建立客户端ipv4 网络环境下的 socket 通信;

因为ipv4和ipv6网络环境下,有很多api不同,因此,不同网络,要做不同判断。

实践证明,如果服务器不是配置的域名,而是配置的Ipv4的一个地址,不会 影响 我们程序的正常解析。

我们可以通过解析出来的 addrinfo结构体中 协议族(AF_INET、AF_INET6),知道当前客户端网络环境是Ipv4还是ipv6。

网络通信部分关键代码:

1.解析服务器的域名(或服务器的 ipv4地址);

2.得到和客户端这边网络环境匹配的ip地址(如果客户端网络环境是ipv4,解析得到的是一个ipv4的地址;如果客户端网络环境是ipv6,解析得到的是一个ipv6的地址)

3.调用相应 网络环境下的 socket连接方法,实现socket的连接。关键代码,已经用红色标识了。

 // TODO:兼容ipv4和IPV6网络环境...
bool TcpClientSocket::ConnectServer(const char *pServerIP,unsigned short ServerPort)
{
struct addrinfo * result = NULL;
struct addrinfo * res = NULL;
int error;
CCLog("TcpClientSocket::function [%s] line [%d] ....传入的参数:pServerIP=%s, ServerPort=%d, ------ ", __FUNCTION__, __LINE__, pServerIP, ServerPort ); error = getaddrinfo(pServerIP, NULL, NULL, &result);
if(error != )
{
// 域名解析失败,直接返回 .....
CCLog("域名解析失败,直接返回 .....TcpClientSocket::function [%s] line [%d] error in pServerIP[%s], port[%d], getaddrinfo:%d, strErr=%s", __FUNCTION__, __LINE__, pServerIP, ServerPort, error, gai_strerror(error));
return false;
} for(res = result; res!=NULL; res = res->ai_next)
{
char hostname[1025] = "";
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, 1025, NULL, 0, 0);
if(error != )
{
CCLog("获取主机信息失败????:TcpClientSocket::function [%s] line [%d] error in pServerIP[%s], port[%d], getnameifno: %s", __FUNCTION__, __LINE__, pServerIP, ServerPort, gai_strerror(error));
continue;
}
else
{
std::string ip = hostname;
switch (res->ai_addr->sa_family)
{
case AF_INET:
{
if(subConnectServerIPV4(ip.c_str(), ServerPort))
{
// IPV4 连接成功
CCLog("TcpClientSocket::IPV4,连接成功了. IP:%s, port:%d", ip.c_str(), ServerPort);
freeaddrinfo(result);
return true;
}
else
{
CloseSocket();
// IPV4 连接失败
CCLog("TcpClientSocket::IPV4,连接失败,继续查找... IP:%s, port:%d", ip.c_str(), ServerPort);
}
}
break; case AF_INET6:
{
if(subConnectServerIPV6(ip.c_str(), ServerPort))
{
// IPV6 连接成功
CCLog("TcpClientSocket::IPV6,连接成功了. IP:%s, port:%d", ip.c_str(), ServerPort);
freeaddrinfo(result);
return true;
}
else
{
CloseSocket();
// IPV6 连接失败
CCLog("TcpClientSocket::IPV6,连接失败,继续查找... IP:%s, port:%d", ip.c_str(), ServerPort);
}
}
break; default:
CCLog("TcpClientSocket::switch (res->ai_addr->sa_family)======= 这是一条异常的log ");
break;
}// end switch
}//end else
}// end for freeaddrinfo(result);
CCLog("TcpClientSocket::Ipv6,Ipv4连接均失败!!! function [%s] line [%d] pServerIP:%s, port:%d ", __FUNCTION__, __LINE__, pServerIP, ServerPort);
return false;
} bool TcpClientSocket::subConnectServerIPV4(const char *pServerIP, unsigned short ServerPort)
{
CCLog("TcpClientSocket::function [%s] line [%d] ip [%s] port [%d]", __FUNCTION__, __LINE__, pServerIP, ServerPort);
struct sockaddr_in addrServer;
int tempSocket = -; memset(&addrServer, , sizeof(addrServer));
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(ServerPort);
addrServer.sin_addr.s_addr = inet_addr(pServerIP);

if((tempSocket = socket(AF_INET,SOCK_STREAM,0)) < )
{

93 CCLOG("TcpClientSocket::function [%s] line [%d]", __FUNCTION__, __LINE__);
return false;
} if(connect(tempSocket, (struct sockaddr*)&addrServer, sizeof(addrServer)) < )
{
CCLOG("TcpClientSocket::function [%s] line [%d]", __FUNCTION__, __LINE__);
return false;
}
return true;
} bool TcpClientSocket::subConnectServerIPV6(const char *pServerIP, unsigned short ServerPort)
{
CCLog("TcpClientSocket::function [%s] line [%d]", __FUNCTION__, __LINE__);
struct sockaddr_in6 addrServer;
int tempSocket = -; memset(&addrServer, , sizeof(addrServer));
addrServer.sin6_family = AF_INET6;
addrServer.sin6_port = htons(ServerPort);
inet_pton(AF_INET6, pServerIP, &addrServer.sin6_addr);
if((tempSocket = socket(AF_INET6,SOCK_STREAM,0)) < )
{
state=NETWORK_STATE_FAILED;
CCLog("TcpClientSocket::%s socket err... line [%d]", __FUNCTION__, __LINE__);
return false;
} if(connect(tempSocket, (struct sockaddr*)&addrServer, sizeof(addrServer)) < )
{
CCLog("TcpClientSocket::%s connect err... line [%d]", __FUNCTION__, __LINE__);

return false;
}
return true;
}

补充:

cocos2d-x工程中,需要升级curl版本。

去cocos2d-x官网下载最新的包(目前最新版本是3.10),找到 curl文件夹,将里面的 文件,替换到你工程对应的curl目录下面。

还需要 替换 libraries文件夹下面的若干 lib库。再在你的工程里面,重新 添加这些库。重新编译工程。

参考连接:

http://www.cnblogs.com/yans/p/5558178.html

http://www.jianshu.com/p/8837739251ad?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weixin-friends

http://blog.csdn.net/chenhanzhun/article/details/41944195

ios 兼容IPV4和IPV6网络通信的更多相关文章

  1. IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类

    一.TCP socket ipv6与ipv4的区别 服务器端源代码如下: #include <stdio.h> #include <stdlib.h> #include < ...

  2. 提升iOS审核通过率之“IPv6兼容测试”

    作者:jingle 腾讯系统测试工程师 商业转载请联系腾讯WeTest授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/285.html 一.背景 在 ...

  3. IPv4和IPv6的兼容问题

    一网络拓扑 Ipv6网络1 路由器A IPv4网络 路由器B IPv6网络2 二知识补充 [注]双协议栈主机(路由器A.B)通过域名解析器区分传过来的是IPv4还是IPv6 三处理技术 双协议栈 Ip ...

  4. IPv4和IPv6的差异;如何实现IPv4和IPv6双协议栈的通信

    1 IPv4和IPv6的差异 1.1 地址空间   IPv6 与 IPv4 比较最显著的一个改动就是使用 128 比特上的地址来代替了 32 比特长的 IPv4 地址. IPv6 中取消了广播地址, ...

  5. ipv4与ipv6 Inet4Address类和Inet6Address类

    在设置本地IP地址的时候,一些人会疑惑IPv4与IPv6的区别是什么?下面由学习啦小编为你分享ipv4与ipv6的区别的相关内容,希望对大家有所帮助. ipv4与ipv6的区别 在windows 7以 ...

  6. RFC2474 - Definition of the Differentiated Services Field (DS Field) in the IPv4 and IPv6 Headers的双语版

    RFC2474 - Definition of the Differentiated Services Field (DS Field) in the IPv4 and IPv6 Headers英文版 ...

  7. IPv4 与 IPv6的区别

    在介绍 IPv4 到 IPv6 区别之前,我们先来简单了解一下 IPv4 和 IPv6. IPv4 网际协议版本4(英语:Internet Protocol version 4,IPv4),又称互联网 ...

  8. IP地址(IPv4)/IPv6地址的正则表达式

    原地址:http://pfeishao.blog.163.com/blog/static/18162337020112113130453/ Pv4地址正则表达式:^((25[0-5]|2[0-4]\d ...

  9. ipv4、ipv6的socket同时监听“bind: Address already in use”的解决方法

    创建ipv4和ipv6的socket,同时监听某个端口的ipv4和ipv6报文,运行时bind函数执行失败,提示“bind: Address already in use”.原因:ipv6的socke ...

随机推荐

  1. linux大于2T的磁盘使用GPT分区方式

    MBR(Master Boot Record)(主引导记录)和GPT(GUID Partition Table)(GUID意为全局唯一标识符)是在磁盘上存储分区信息的两种不同方式 对于传统的MBR分区 ...

  2. Codeforces Wilbur and Array

    Description Wilbur the pig is tinkering with arrays again. He has the array a1, a2, ..., an initiall ...

  3. [iOS基础控件 - 6.2] LOL英雄列表 UITableView单项显示

    A.需求 1.使用只有一个section的TableView来显示LOL 的英雄列表 2.内容包括标题.副标题.图标 3.使用plain样式 4.使用MVC模式     heros.plist 文件结 ...

  4. 关于Windows文件名和路径名的那些事

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:关于Windows文件名和路径名的那些事.

  5. 剑指OFFER之数组中出现次数超过一半的数字(九度OJ1370)

    题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2 ...

  6. 【Cocos2d-X开发学习笔记】第09期:渲染框架之菜单类(CCMenu)的使用

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010    一.菜单项(CCMenuItem) 菜单项 ...

  7. SVN的版本日期

    SVN还可以使用版本日期来指定某个版本,日期格式使用ISO-8601标准,一般是yyyy-mm-dd hh:mm:ss.当你指定一个日期,SVN会在版本库中找到最接近这个日期的版本. SVN对日期的解 ...

  8. JavaScript中的Partial Application和Currying

    这篇文章是一篇学习笔记,记录我在JS学习中的一个知识点及我对它的理解,知识点和技巧本身并不是我原创的.(引用或参考到的文章来源在文末) 先不解释Partial Application(偏函数应用)和C ...

  9. WM_VSCROLL

    关键点 控制滚动条在最下面 实现过程 SendMessage(form1.Memo1.Handle,WM_VSCROLL,SB_BOTTOM,0); 图 备注 相关链接   来自为知笔记(Wiz)

  10. zendserver 安装 ZendDebugger

    网上都找不到支持PHP5.3及以上的Zend Debugger,然后下载了ZendStudio 10.1,发现它内置的PHP 5.3 和 5.4都支持Debugger, 这Debugger就是Zend ...