unity3d ipv6支持
unity游戏应用提交app stroe需要通过ipv6测试,但是unity本身我没找到可用的接口,所以使用ios插件来处理。
插件的IOSNativeNet.h和IOSNativeNet.m代码:
IOSNativeNet.h
@interface BundleId : NSObject +(NSString *)getIPv6:(const char*)mHost:(const char*)mPort; @end
IOSNativeNet.m
#import "IOSNativeNet.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); }
在unity中C#调用插件的代码:
using System; using System.Net.Sockets; namespace SDK.Lib { public class IOSNativeNetImport { [System.Runtime.InteropServices.DllImport("__Internal")] private static extern string getIPv6(string mHost, string mPort); //"192.168.1.1&&ipv4" 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 } static public void getIPType(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)) { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("IOSNativeNetImport::getIPType, mIPv6 not empty, mIPv6 = {0}", mIPv6), SDK.Lib.LogTypeId.eLogNetwork); } string[] m_StrTemp = System.Text.RegularExpressions.Regex.Split(mIPv6, "&&"); if (m_StrTemp != null && m_StrTemp.Length >= 2) { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("IOSNativeNetImport::getIPType, m_StrTemp not empty, m_StrTemp[1] = {0}", m_StrTemp[1]), SDK.Lib.LogTypeId.eLogNetwork); } string IPType = m_StrTemp[1]; if (IPType == "ipv6") { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("IOSNativeNetImport::getIPType, IPType is ipv6, m_StrTemp[0] = {0}", m_StrTemp[0]), SDK.Lib.LogTypeId.eLogNetwork); } newServerIp = m_StrTemp[0]; mIPType = AddressFamily.InterNetworkV6; } else { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("IOSNativeNetImport::getIPType, IPType is not ipv6, m_StrTemp[0] = {0}", m_StrTemp[0]), SDK.Lib.LogTypeId.eLogNetwork); } } } else { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log("IOSNativeNetImport::getIPType, m_StrTemp empty", SDK.Lib.LogTypeId.eLogNetwork); } } } else { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log("IOSNativeNetImport::getIPType, mIPv6 empty, mIPv6 = {0}", SDK.Lib.LogTypeId.eLogNetwork); } } } catch (Exception e) { //ClientLog.Instance.Log("GetIPv6 error: " + e); if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("IOSNativeNetImport::getIPType, error, exception = {0}", e), SDK.Lib.LogTypeId.eLogNetwork); } } } static public void SocketClient(String serverIp, String serverPorts) { String newServerIp = ""; AddressFamily newAddressFamily = AddressFamily.InterNetwork; getIPType(serverIp, serverPorts, out newServerIp, out newAddressFamily); if (!string.IsNullOrEmpty(newServerIp)) { serverIp = newServerIp; } Socket socketClient = new Socket(newAddressFamily, SocketType.Stream, ProtocolType.Tcp); //ClientLog.Instance.Log("Socket AddressFamily: " + newAddressFamily.ToString() + "ServerIp:" + serverIp); } } }
最后是通过ip和port连接服务器是调用的方法:
public void Connect(string ip, int port) { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("SocketChannel::Connect, start, ip = {0} port = {1}", ip, port), SDK.Lib.LogTypeId.eLogNetwork); } if (!_IsConnected()) { string newServerIp = ""; AddressFamily newAddressFamily = AddressFamily.InterNetwork; //var address = Dns.GetHostAddresses(ip)[0]; SDK.Lib.IOSNativeNetImport.getIPType(ip, port.ToString(), out newServerIp, out newAddressFamily); if (SDK.Lib.MacroDef.ENABLE_LOG) { //SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("SocketChannel::Connect, address = {0} AddressFamily = {1}", address, address.AddressFamily), SDK.Lib.LogTypeId.eLogNetwork); SDK.Lib.Ctx.mInstance.mLogSys.log(string.Format("SocketChannel::Connect, curIp = {0} newIp = {1} AddressFamily = {2}", ip, newServerIp, newAddressFamily), SDK.Lib.LogTypeId.eLogNetwork); } ip = newServerIp; //this.socket = new Socket(address.AddressFamily, ProtocolType.Tcp == this.type ? SocketType.Stream : SocketType.Dgram, this.type); //this.socket.BeginConnect(new IPEndPoint(address, port), new AsyncCallback(_ConnectCallback), this.socket); this.socket = new Socket(newAddressFamily, ProtocolType.Tcp == this.type ? SocketType.Stream : SocketType.Dgram, this.type); this.socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ip), port), new AsyncCallback(_ConnectCallback), this.socket); _NotifyChannelStateChange(ChannelState.CONNECTING); } else { if (SDK.Lib.MacroDef.ENABLE_LOG) { SDK.Lib.Ctx.mInstance.mLogSys.log("SocketChannel::Connect, Connected", SDK.Lib.LogTypeId.eLogNetwork); } _NotifyChannelStateChange(ChannelState.CONNECTED); } }
ios插件如何使用可参照我的前一篇随笔:http://www.cnblogs.com/lan-yt/p/6934155.html