Unity之KBEngin-发布Ios的Ipv6过审问题

 一.Ios过审的Ipv6问题

IOS官方返回的的报文中包含IPv6的文字,说明是App不兼容Ipv6网络地址引起的,确保App在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的地址返回给客户端。

三.如何解决 

苹果审核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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨守星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值