1. 程式人生 > >蘋果ios應用的網路ipv6適配攻略

蘋果ios應用的網路ipv6適配攻略

蘋果要求在2016年6月1日後新的app必須支援ipv6網路, 技術發展靠蘋果果然沒錯, 但開發者還是要開始忙起來了
這裡介紹下Unity3D的適配的一些經驗

基本注意點

  • ios ipv6適配無需修改伺服器, 也就是說, 如果你的伺服器依然是ipv4的也是可以使用的
  • 蘋果的適配方案是將ipv4的地址轉換為ipv6, 到了路由層再轉回去繼續利用ipv4網路傳輸

測試網路環境搭建

  • 無需路由器支援ipv6, 但貓(modem)必須要支援ipv6. 因為現在大多數都是光貓
    以下截圖是光貓管理端
    3440e3f9-12de-435b-85ab-a7a3be8b384b[6]
    光貓裡的ipv6支援預設是關閉的, 所以需要手動開啟, 按預設值配置即可

  • 請確認mac os系統必須是osx 10.11以後的版本才可以開啟NAT64

  • 正確連線mac的ios裝置應是如下截圖示意
    91f54476-4b5d-4585-a364-0da2139774c1[6]

  • 預設連線上wifi時看連線資訊時, 一般只會有紅色DNS地址或者根本不顯示
  • 只有在第一次訪問網路, 例如開啟瀏覽器進入任意網站時, 才會顯示上面的幾條資訊
  • 如果只有DNS沒有IP地址和子網掩碼, 一般是光貓沒有開啟ipv6的DHCP, 沒有分配IP
  • 還有一種測試ipv6 DHCP是否正常工作的方法: 關閉NAT64時可以上網, 但開啟NAT64無法上網

Unity3D的Socket適配

WWW類本身已經支援了IPV6, 無需處理, 這裡講解使用C#原生Socket的處理

  • 測試用的裝置的iOS版本必須是9.3以上的
  • Socket構造時, AddressFamily 設定為InterNetworkV6時只支援ipv6網路, 傳入InterNetwork時只支援ipv4網路
  • 4.7.2和5.4.3的當前版本在mono層並未支援ipv6程式碼適配的核心函式getaddrinfo, 因此需要通過oc層做轉換, 以下是程式碼
    這段程式碼將getaddrinfo的地址轉換成一個完整字串, 格式是:
    ipv4|ipv4地址|ipv6|ipv6地址|

iosaddrinfo.mm

   1:  #include <sys/socket.h>
   2:  #include <netdb.h>
   3:  #include <arpa/inet.h>
   4:  #include <err.h>
   5:  #define OUTSTR_SIZE 4096
   6:  extern "C"
   7:  {
   8:      const char* copyStr( const char* str )
   9:      {
  10:          char* s = (char*)malloc(strlen(str) + 1);
  11:          strcpy(s, str);
  12:          return s;
  13:      }
  14:      const char* IOSGetAddressInfo(const char *host )
  15:      {
  16:          if( NULL == host )
  17:              return copyStr("ERROR_HOSTNULL");
  18:          char outstr[OUTSTR_SIZE];
  19:          struct addrinfo hints, *res, *res0;
  20:          memset(&hints, 0, sizeof(hints));
  21:          hints.ai_family = PF_UNSPEC;
  22:          hints.ai_socktype = SOCK_STREAM;
  23:          hints.ai_flags = AI_DEFAULT;
  24:          printf("getaddrinfo: %s\n", host);
  25:          int error = getaddrinfo(host, "http", &hints, &res0);
  26:          if (error != 0 )
  27:          {
  28:              printf("getaddrinfo: %s\n", gai_strerror(error));
  29:              return copyStr("ERROR_GETADDR");
  30:          }
  31:          memset( outstr, 0, sizeof(char)*OUTSTR_SIZE );
  32:          struct sockaddr_in6* addr6;
  33:          struct sockaddr_in* addr;
  34:          const char* solvedaddr;
  35:          char ipbuf[32];
  36:          for (res = res0; res; res = res->ai_next)
  37:          {
  38:              if (res->ai_family == AF_INET6)
  39:              {
  40:                  addr6 =( struct sockaddr_in6*)res->ai_addr;
  41:                  solvedaddr = inet_ntop(AF_INET6, &addr6->sin6_addr, ipbuf, sizeof(ipbuf));
  42:                  strcat ( outstr, "ipv6|");
  43:                  strcat ( outstr, solvedaddr);
  44:              }
  45:              else
  46:              {
  47:                  addr =( struct sockaddr_in*)res->ai_addr;
  48:                  solvedaddr = inet_ntop(AF_INET, &addr->sin_addr, ipbuf, sizeof(ipbuf));
  49:                  strcat ( outstr, "ipv4|");
  50:                  strcat ( outstr, solvedaddr);
  51:              }
  52:              strcat ( outstr, "|");
  53:          }
  54:          return copyStr(outstr);
  55:      }
  56:  }

iosaddrinfo.h

   1:  #pragma once
   2:  extern "C"{
   3:      const char* IOSGetAddressInfo(const char *host );
   4:  }
  • C#層的處理假設多個地址中都是統一的地址型別,要麼全是v4要麼全是v6
    返回給定的host內多個IP地址, 可以供處理複雜的北網通,南電信問題
   1:  using System;
   2:  using System.Net;
   3:  using System.Net.Sockets;
   4:  using System.Runtime.InteropServices;
   5:  using UnityEngine;
   6:  using System.Collections;
   7:  using System.Collections.Generic;
   8:  public class IOSIPV6
   9:  {
  10:      [DllImport("__Internal")]
  11:      private static extern string IOSGetAddressInfo(string host );  
  12:      public static IPAddress[] ResolveIOSAddress(string host, out AddressFamily af)
  13:      {
  14:          af = AddressFamily.InterNetwork;
  15:          var outstr = IOSGetAddressInfo(host);
  16:          Debug.Log("IOSGetAddressInfo: " + outstr);
  17:          if (outstr.StartsWith ("ERROR")) 
  18:          {
  19:              return null;
  20:          }
  21:          var addressliststr = outstr.Split('|');
  22:          var addrlist = new List<IPAddress>();
  23:          foreach (string s in addressliststr)
  24:          {
  25:              if (String.IsNullOrEmpty(s.Trim()))
  26:                  continue;
  27:              switch( s )
  28:              {
  29:                  case "ipv6":
  30:                      {                        
  31:                          af = AddressFamily.InterNetworkV6;
  32:                      }
  33:                      break;
  34:                  case "ipv4":
  35:                      {
  36:                          af = AddressFamily.InterNetwork;
  37:                      }
  38:                      break;
  39:                  default:
  40:                      {
  41:                          addrlist.Add(IPAddress.Parse(s));
  42:                      }
  43:                      break;
  44:              }
  45:          }
  46:          return addrlist.ToArray();
  47:      }
  48:  }

參考連結