ios 兼容IPV4和IPV6网络通信
前言:
苹果官方出了新的规定,要求新上架的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://blog.csdn.net/chenhanzhun/article/details/41944195
ios 兼容IPV4和IPV6网络通信的更多相关文章
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
一.TCP socket ipv6与ipv4的区别 服务器端源代码如下: #include <stdio.h> #include <stdlib.h> #include < ...
- 提升iOS审核通过率之“IPv6兼容测试”
作者:jingle 腾讯系统测试工程师 商业转载请联系腾讯WeTest授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/285.html 一.背景 在 ...
- IPv4和IPv6的兼容问题
一网络拓扑 Ipv6网络1 路由器A IPv4网络 路由器B IPv6网络2 二知识补充 [注]双协议栈主机(路由器A.B)通过域名解析器区分传过来的是IPv4还是IPv6 三处理技术 双协议栈 Ip ...
- IPv4和IPv6的差异;如何实现IPv4和IPv6双协议栈的通信
1 IPv4和IPv6的差异 1.1 地址空间 IPv6 与 IPv4 比较最显著的一个改动就是使用 128 比特上的地址来代替了 32 比特长的 IPv4 地址. IPv6 中取消了广播地址, ...
- ipv4与ipv6 Inet4Address类和Inet6Address类
在设置本地IP地址的时候,一些人会疑惑IPv4与IPv6的区别是什么?下面由学习啦小编为你分享ipv4与ipv6的区别的相关内容,希望对大家有所帮助. ipv4与ipv6的区别 在windows 7以 ...
- 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英文版 ...
- IPv4 与 IPv6的区别
在介绍 IPv4 到 IPv6 区别之前,我们先来简单了解一下 IPv4 和 IPv6. IPv4 网际协议版本4(英语:Internet Protocol version 4,IPv4),又称互联网 ...
- IP地址(IPv4)/IPv6地址的正则表达式
原地址:http://pfeishao.blog.163.com/blog/static/18162337020112113130453/ Pv4地址正则表达式:^((25[0-5]|2[0-4]\d ...
- ipv4、ipv6的socket同时监听“bind: Address already in use”的解决方法
创建ipv4和ipv6的socket,同时监听某个端口的ipv4和ipv6报文,运行时bind函数执行失败,提示“bind: Address already in use”.原因:ipv6的socke ...
随机推荐
- JavaScript获取HTML页面源代码
来自:http://www.cnblogs.com/luckbird/archive/2008/02/01/1061048.html <a href="javascript:gets( ...
- SQL Server中取两个表的交集,并集和差集
在项目中遇到要取两个表差集的情况 假设有两个表tblNZPostCodes, NZPostcode 两个表中存储的都是新西兰的post code信息,字段一致,只是数据上有所差异. 1. Union ...
- 转载c#泛型 类型参数的约束(c#编程指南)
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制.如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误.这些限制称为约束.约束是使用 where 上 ...
- C++学习笔记(八):函数重载、函数指针和函数对象
函数重载 函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数.重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于 ...
- iOS中的深复制与浅复制
很多语言中都有深复制浅复制的概念,如C++,ObjC等.简单来说,浅复制就是两个变量指向了同一块内存区域,深复制就是两个变量指向了不同的内存区域,但是两个内存区域里面的内容是一样的. 浅复制示意图: ...
- cocos2dx windows phone平台下CCLabelTTF自己主动换行的实现(2)
前几天发过一篇文章说怎样实现wp8下的CCLabelTTF怎样自己主动换行,后来发现果如预料的那般.效果非常不好.主要是非等宽字体的情况下看着非常糟心.因此再改动了一版.效果要好非常多了. 详细实现事 ...
- Windows下配置PHP支持LDAP扩展方法(wampserver)
在网上搜了好多文章都不行呢,大都是没有开启扩展的问题,可是我的是开启的. 终于看到一篇文章,因为我用的是wampserver.下面是文章原话: 然后你发现上面的提示依旧,因为这是网上大多能查到的资料的 ...
- Codeforces Round #324 (Div. 2) C. Marina and Vasya 贪心
C. Marina and Vasya Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/584/pr ...
- SqlServer按照指定顺序对字段进行排序
最近的一个项目,使用存储过程对报表进行分析,其中有一些名称需要根据指定顺序显示,而其名称对应的编号并不是按照要求的顺序排列的.通过上网查找资料,发现sql 中的charindex函数可以帮助解决这个问 ...
- Java算法实例集合
这里是princeton搜集的算法课程Java示例.包括超过了100 Java个算法程序源码.Javadoc和测试数据.点击这里查看.