一.Ios過審的Ipv6問題
IOS官方傳回的的封包中包含IPv6的文字,說明是App不相容Ipv6網絡位址引起的,確定App在Ipv6的環境下能夠正常運作。
Unity之KBEngin-釋出Ios的Ipv6過審問題
二.什麼是Ipv6
IPV6,是對IPV4位址空間的擴充。目前當我們用iOS裝置連接配接上Wifi、4G、3G等網絡時,裝置被配置設定的位址均是IPV4位址,但是随着營運商和企業逐漸部署IPV6 DNS64/NAT64網絡之後,裝置被配置設定的位址會變成IPV6的位址,而這些網絡就是所謂的IPV6-Only網絡,并且仍然可以通過此網絡去擷取IPV4位址提供的内容。用戶端向伺服器端請求域名解析,首先通過DNS64 Server查詢IPv6的位址,如果查詢不到,再向DNS Server查詢IPv4位址,通過DNS64 Server合成一個IPV6的位址,最終将一個IPV6的位址傳回給用戶端。
Unity之KBEngin-釋出Ios的Ipv6過審問題
三.如何解決
蘋果稽核Ipv6的标準是確定應用在Ipv6的環境下能夠正常運作
Ipv6網絡下的用戶端是不能連接配接Ipv4的服務端的,需要通過DNS64或者NAT64的轉換位址
DNS64/NAT64是蘋果提供的轉換通道,不需要開發者去考慮這個問題 ,隻需要在發送連接配接請求時,根據目前網絡環境去轉換實際的連接配接位址,例如Ipv6,需要通過調用IOS官方提供的轉換通道請求實際的連接配接位址
四.編寫Ios位址轉換的接口
建立兩個記事本,并把名稱帶字尾分别修改成ipv6.h和ipv6.m,ipv6為名稱(可以自定義)
編輯ipv6.h,輸入以下代碼 @interface BundleId : NSObject
+(NSString *)getIPv6 : (const char *)mHost :(const char *)mPort;
@end
編輯ipv6.m,輸入以下代碼 #import "BundleId.h"
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>
#define MakeStringCopy( _x_ ) ( _x_ != NULL && [_x_ isKindOfClass:[NSString class]] ) ? strdup( [_x_ UTF8String] ) : NULL
const char* getIPv6(const char *mHost,const char *mPort)
{
if( nil == mHost )
return NULL;
const char *newChar = "No";
const char *cause = NULL;
struct addrinfo* res0;
struct addrinfo hints;
struct addrinfo* res;
int n, s;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_DEFAULT;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((n=getaddrinfo(mHost, "http", &hints, &res0))!=0)
{
printf("getaddrinfo error: %s\n",gai_strerror(n));
return NULL;
}
struct sockaddr_in6* addr6;
struct sockaddr_in* addr;
NSString * NewStr = NULL;
char ipbuf[32];
s = -1;
for(res = res0; res; res = res->ai_next)
{
if (res->ai_family == AF_INET6)
{
addr6 =( struct sockaddr_in6*)res->ai_addr;
newChar = inet_ntop(AF_INET6, &addr6->sin6_addr, ipbuf, sizeof(ipbuf));
NSString * TempA = [[NSString alloc] initWithCString:(const char*)newChar
encoding:NSASCIIStringEncoding];
NSString * TempB = [NSString stringWithUTF8String:"&&ipv6"];
NewStr = [TempA stringByAppendingString: TempB];
printf("%s\n", newChar);
}
else
{
addr =( struct sockaddr_in*)res->ai_addr;
newChar = inet_ntop(AF_INET, &addr->sin_addr, ipbuf, sizeof(ipbuf));
NSString * TempA = [[NSString alloc] initWithCString:(const char*)newChar
encoding:NSASCIIStringEncoding];
NSString * TempB = [NSString stringWithUTF8String:"&&ipv4"];
NewStr = [TempA stringByAppendingString: TempB];
printf("%s\n", newChar);
}
break;
}
freeaddrinfo(res0);
printf("getaddrinfo OK");
NSString * mIPaddr = NewStr;
return MakeStringCopy(mIPaddr);
}
儲存ipv6.m和ipv6.h,并把它們放在Unity的Plugins/IOS的目錄下
五.結合編輯的工具,解決Ipv6問題
編輯DNSParse.cs,輸入以下代碼,調用上一步編輯的接口 //調用工具的接口
#if UNITY_IPHONE
[DllImport("__Internal")]
private static extern string getIPv6(string mHost, string mPort);
#endif
/// <summary>
/// 擷取Ipv6位址,位址格式為"192.168.1.1&&ipv4"用于解析位址
/// </summary>
/// <param name="mHost">域名</param>
/// <param name="mPort">端口</param>
/// <returns></returns>
public static string GetIPv6(string mHost, string mPort)
{
#if UNITY_IPHONE && !UNITY_EDITOR
string mIPv6 = getIPv6(mHost, mPort);
return mIPv6;
#else
return mHost + "&&ipv4";
#endif
}
/// <summary>
/// 解析位址
/// </summary>
/// <param name="serverIp">域名</param>
/// <param name="serverPorts">端口</param>
/// <param name="newServerIp">輸出新的位址</param>
/// <param name="mIPType">網絡類型</param>
public static void PareseIP(string serverIp, string serverPorts, out string newServerIp, out AddressFamily mIPType)
{
mIPType = AddressFamily.InterNetwork;
newServerIp = serverIp;
try
{
string mIPv6 = GetIPv6(serverIp, serverPorts);
if (!string.IsNullOrEmpty(mIPv6))
{
string[] m_StrTemp = System.Text.RegularExpressions.Regex.Split(mIPv6, "&&");
if (m_StrTemp != null && m_StrTemp.Length >= 2)
{
string IPType = m_StrTemp[1];
if (IPType == "ipv6")
{
newServerIp = m_StrTemp[0];
mIPType = AddressFamily.InterNetworkV6;
}
}
}
}
catch (Exception e)
{
Debug.Log("解析出錯,錯誤類型:"+e.Message);
}
}
查詢NetworkInterface.cs腳本(Kbengine用戶端導出包中的類),定位到connectTo的方法,修改如下 public void connectTo(string ip, int port, ConnectCallback callback, object userData)
{
if (valid())
throw new InvalidOperationException("Have already connected!");
string newServerIp = "";
AddressFamily newAddressFamily = AddressFamily.InterNetwork;
//解析是否是Ipv6位址,如果是傳回Ipv6位址,如果不是保持原來位址不變
DNSParase.PareseIP(ip, port.ToString(), out newServerIp, out newAddressFamily);
if (!string.IsNullOrEmpty(newServerIp)) { ip = newServerIp; }
Dbg.DEBUG_MSG("擷取的Ip:"+ip+" 協定:"+newAddressFamily);
_socket = new Socket(newAddressFamily, SocketType.Stream, ProtocolType.Tcp);
_socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, KBEngineApp.app.getInitArgs().getRecvBufferSize() * 2);
_socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, SocketOptionName.SendBuffer, KBEngineApp.app.getInitArgs().getSendBufferSize() * 2);
_socket.NoDelay = true;
//_socket.Blocking = false;
ConnectState state = new ConnectState();
state.connectIP = ip;
state.connectPort = port;
state.connectCB = callback;
state.userData = userData;
state.socket = _socket;
state.networkInterface = this;
Dbg.DEBUG_MSG("connect to " + ip + ":" + port + " ...");
connected = false;
// 先注冊一個事件回調,該事件在目前線程觸發
Event.registerIn("_onConnectionState", this, "_onConnectionState");
var v = new AsyncConnectMethod(this._asyncConnect);
v.BeginInvoke(state, new AsyncCallback(this._asyncConnectCB), state);
}
注意事項,網絡通信使用域名連接配接
測試環境搭建相關文章 https://blog.csdn.net/iosworker/article/details/51595432