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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM