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的连接。关键代码,已经用红色标识了。

  1 // TODO:兼容ipv4和IPV6网络环境...
  2 bool TcpClientSocket::ConnectServer(const char *pServerIP,unsigned short ServerPort)
  3 {
  4     struct addrinfo * result = NULL;
  5     struct addrinfo * res = NULL;
  6     int error;
  7     CCLog("TcpClientSocket::function [%s] line [%d] ....传入的参数:pServerIP=%s, ServerPort=%d, ------ ", __FUNCTION__, __LINE__, pServerIP, ServerPort );
  8     
  9     error = getaddrinfo(pServerIP, NULL, NULL, &result);
 10     if(error != 0)
 11     {
 12         // 域名解析失败,直接返回 .....
 13         CCLog("域名解析失败,直接返回 .....TcpClientSocket::function [%s] line [%d] error in pServerIP[%s], port[%d], getaddrinfo:%d, strErr=%s", __FUNCTION__, __LINE__, pServerIP, ServerPort, error, gai_strerror(error));
 14         return false;
 15     }
 16     
 17     for(res = result; res!=NULL; res = res->ai_next)
 18     {
 19         char hostname[1025] = "";
 20         error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, 1025, NULL, 0, 0);
 21         if(error != 0)
 22         {
 23             CCLog("获取主机信息失败????:TcpClientSocket::function [%s] line [%d] error in  pServerIP[%s], port[%d], getnameifno: %s", __FUNCTION__, __LINE__, pServerIP, ServerPort, gai_strerror(error));
 24             continue;
 25         }
 26         else
 27         {
 28             std::string ip = hostname;
 29             switch (res->ai_addr->sa_family)
 30             {
 31                 case AF_INET:
 32                 {
 33                     if(subConnectServerIPV4(ip.c_str(), ServerPort))
 34                     {
 35                         // IPV4 连接成功
 36                         CCLog("TcpClientSocket::IPV4,连接成功了. IP:%s, port:%d", ip.c_str(), ServerPort);
 37                         freeaddrinfo(result);
 38                         return true;
 39                     }
 40                     else
 41                     {
 42                         CloseSocket();
 43                         // IPV4 连接失败
 44                         CCLog("TcpClientSocket::IPV4,连接失败,继续查找... IP:%s, port:%d", ip.c_str(), ServerPort);
 45                     }
 46                 }
 47                     break;
 48                     
 49                 case AF_INET6:
 50                 {
 51                     if(subConnectServerIPV6(ip.c_str(), ServerPort))
 52                     {
 53                         // IPV6 连接成功
 54                         CCLog("TcpClientSocket::IPV6,连接成功了. IP:%s, port:%d", ip.c_str(), ServerPort);
 55                         freeaddrinfo(result);
 56                         return true;
 57                     }
 58                     else
 59                     {
 60                         CloseSocket();
 61                         // IPV6 连接失败
 62                         CCLog("TcpClientSocket::IPV6,连接失败,继续查找... IP:%s, port:%d", ip.c_str(), ServerPort);
 63                     }
 64                 }
 65                     break;
 66                     
 67                 default:
 68                     CCLog("TcpClientSocket::switch (res->ai_addr->sa_family)=======   这是一条异常的log  ");
 69                     break;
 70             }// end switch
 71         }//end else
 72     }// end for
 73     
 74     freeaddrinfo(result);
 75     CCLog("TcpClientSocket::Ipv6,Ipv4连接均失败!!! function [%s] line [%d] pServerIP:%s, port:%d ", __FUNCTION__, __LINE__, pServerIP, ServerPort);
 76     return false;
 77 }
 78 
 79 bool TcpClientSocket::subConnectServerIPV4(const char *pServerIP, unsigned short ServerPort)
 80 {
 81     CCLog("TcpClientSocket::function [%s] line [%d] ip [%s] port [%d]", __FUNCTION__, __LINE__, pServerIP, ServerPort);
 82     struct sockaddr_in     addrServer;
 83     int tempSocket = -1;
 84     
 85     memset(&addrServer, 0, sizeof(addrServer));
 86     addrServer.sin_family = AF_INET;
 87     addrServer.sin_port = htons(ServerPort);
 88     addrServer.sin_addr.s_addr = inet_addr(pServerIP);
 89     
 90     if((tempSocket = socket(AF_INET,SOCK_STREAM,0)) < 0)
 91     {
 92          
93
CCLOG("TcpClientSocket::function [%s] line [%d]", __FUNCTION__, __LINE__); 94 return false; 95 } 96 97 if(connect(tempSocket, (struct sockaddr*)&addrServer, sizeof(addrServer)) < 0) 98 { 99 CCLOG("TcpClientSocket::function [%s] line [%d]", __FUNCTION__, __LINE__); 100 return false; 101 } 102 return true; 103 } 104 105 bool TcpClientSocket::subConnectServerIPV6(const char *pServerIP, unsigned short ServerPort) 106 { 107 CCLog("TcpClientSocket::function [%s] line [%d]", __FUNCTION__, __LINE__); 108 struct sockaddr_in6 addrServer; 109 int tempSocket = -1; 110 111 memset(&addrServer, 0, sizeof(addrServer)); 112 addrServer.sin6_family = AF_INET6; 113 addrServer.sin6_port = htons(ServerPort); 114 inet_pton(AF_INET6, pServerIP, &addrServer.sin6_addr); 115 if((tempSocket = socket(AF_INET6,SOCK_STREAM,0)) < 0) 116 { 117 state=NETWORK_STATE_FAILED; 118 CCLog("TcpClientSocket::%s socket err... line [%d]", __FUNCTION__, __LINE__); 119 return false; 120 } 121 122 if(connect(tempSocket, (struct sockaddr*)&addrServer, sizeof(addrServer)) < 0) 123 { 124 CCLog("TcpClientSocket::%s connect err... line [%d]", __FUNCTION__, __LINE__); 125
126 return false; 127 } 128 return true; 129 }

 

补充:

    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

转载于:https://www.cnblogs.com/MasterOogway/p/5778408.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值