前言:
蘋果官方出了新的規定,要求新上架的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庫。再在你的工程里面,重新 添加這些庫。重新編譯工程。

參考連接:
