Unity Ipv6 Support

2016/06/14 unity ipv6

Unity支持ipv6的简易方法

原因

  1. 苹果突然宣布2016.6.1之后提交的应用必须通过ipv6审核
  2. 我们的项目中大量使用的socket tcpclient等api

环境搭建

  1. 找一个mac
  2. 偏好设置中按住 command 键 点开 共享
  3. 分享wifi 勾上 nat64
  4. 手机连上这个wifi即可

解决思路

  1. 需要判断是否为 ipv6-only 的环境
    1. 通过dns api 即可得到返回
  2. 需要将现有的ipv4地址转换为ipv6
    1. ipv6的socket必须使用ipv6的地址
    2. ipv4转ipv6的转换机制很多,苹果希望的是 NAT64/DNS64 即 64:ff9b::/96

代码

代码不多直接贴上来了

public class SocketHelper
{
    private static bool? mIsIpv6Only;

    /// <summary>
    /// 判断是否为Ipv6-only环境 
    /// Dns.GetHostAddresses 为耗时操作
    /// </summary>
    public static bool IsIpv6Only
    {
        get
        {
#if UNITY_IPHONE
            if (mIsIpv6Only.HasValue)
                return mIsIpv6Only.Value;
            else
            {
                IPAddress[] addrs = null;
                try
                {
                    addrs = Dns.GetHostAddresses("www.qq.com");
                }
                catch(Exception ex)
                {
                    Debug.LogError(ex.Message);
                }

                if (addrs == null || addrs.Length == 0)
                {
                    mIsIpv6Only = false;
                    return mIsIpv6Only.Value;
                }

                // 优先选用ipv4的模式
                var haveIpv4 = false;
                foreach (var addr in addrs)
                {
                    if (addr.AddressFamily == AddressFamily.InterNetwork)
                        haveIpv4 = true;
                    else if (addr.AddressFamily == AddressFamily.InterNetworkV6)
                        mIsIpv6Only = true;
                }

                if (haveIpv4)
                {
                    mIsIpv6Only = false;
                }
                return mIsIpv6Only.Value;
            }
#endif

            return false;
        }
    }

    /// <summary>
    /// 根据Dns情况自动创建基于 ipv6 或者 ipv4 的 AddressFamily 
    /// </summary>
    public static AddressFamily AddressFamily
    {
        get
        {
            var ret = AddressFamily.InterNetwork;
            if (IsIpv6Only)
                ret = AddressFamily.InterNetworkV6;
            return ret;
        }
    }

    /// <summary>
    /// 根据Dns情况自动创建基于 ipv6 或者 ipv4的Socket 
    /// </summary>
    /// <param name="protocolType"></param>
    /// <param name="socketType">  </param>
    /// <returns></returns>
    public static Socket createSocket(ProtocolType protocolType, SocketType socketType = SocketType.Stream)
    {
        return new Socket(AddressFamily, socketType, protocolType);
    }


    /// <summary>
    /// 转换ip (ipv6用ipv6的ip地址)
    /// </summary>
    /// <param name="srcIp"></param>
    /// www.qq.com return www.qq.com
    /// fe80:fe80::fe80... return fe80:fe80::fe80...
    /// 182.254.139.22 retun 64:ff9b::b6fe:8b16
    /// <returns></returns>
    public static string praseIPStr(string srcIp)
    {
        if (!IsIpv6Only)
            return srcIp;

        if (!Regex.IsMatch(srcIp, @"((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))"))
            return srcIp;

        return praseIpv4ToIpv6(srcIp);
    }

    /// <summary>
    /// ipv4 to ipv6
    /// </summary>
    /// <param name="srcIp"></param>
    /// <returns></returns>
    private static string praseIpv4ToIpv6(string srcIp)
    {
        var values = srcIp.splitToIntArray('.');
        if (values == null || values.Length != 4)
            return srcIp;

        var ret = "64:ff9b::";
        ret += Convert.ToString(values[0], 16);
        ret += Convert.ToString(values[1], 16);
        ret += ":";
        ret += Convert.ToString(values[2], 16);
        ret += Convert.ToString(values[3], 16);
        return ret;
    }
}

结语

对网络通信这一块还不太熟悉,苹果的建议是不要使用低级api like socket…

参考资料

  1. 一篇关于ipv6的文章
  2. 苹果官方的文档
  3. Unity官方的文档

Search

    Post Directory