【问题标题】:How to get IP address of device in Unity 2018+?如何在 Unity 2018+ 中获取设备的 IP 地址?
【发布时间】:2019-01-29 05:49:43
【问题描述】:

如何在Unity 2018.2+为安卓设备开发的程序中获取C#的IP地址?

似乎Network.player.ipAddress 现在已被弃用,所以我正在寻找一种新方法。

【问题讨论】:

  • 我搜索过了。但在 Stack 上没有关于它的新信息。仅讨论获取 ip 的旧方法,目前已弃用。
  • ALERT - 现在(2018 年末?)您似乎可以直接调用 nc.address
  • 稍后 - 这是最新 Unity 中的终于解决。见长的第二个答案。

标签: c# unity3d ip ip-address


【解决方案1】:

Network.player.ipAddress 已被弃用,因为它基于旧的过时 Unity 网络系统。

如果你使用Unity新的uNet网络系统,可以使用NetworkManager.networkAddress

string IP = NetworkManager.singleton.networkAddress;

如果您使用原始网络协议和 API,如 TCP/UDP,则必须使用 NetworkInterface API 来查找 IP 地址。我使用IPManager,它在桌面和移动设备上都适用于我:

IPv4

string ipv4 = IPManager.GetIP(ADDRESSFAM.IPv4);

IPv6

string ipv6 = IPManager.GetIP(ADDRESSFAM.IPv6);

IPManager 类:

using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

public class IPManager
{
    public static string GetIP(ADDRESSFAM Addfam)
    {
        //Return null if ADDRESSFAM is Ipv6 but Os does not support it
        if (Addfam == ADDRESSFAM.IPv6 && !Socket.OSSupportsIPv6)
        {
            return null;
        }

        string output = "";

        foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
        {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
            NetworkInterfaceType _type1 = NetworkInterfaceType.Wireless80211;
            NetworkInterfaceType _type2 = NetworkInterfaceType.Ethernet;

            if ((item.NetworkInterfaceType == _type1 || item.NetworkInterfaceType == _type2) && item.OperationalStatus == OperationalStatus.Up)
#endif 
            {
                foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
                {
                    //IPv4
                    if (Addfam == ADDRESSFAM.IPv4)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            output = ip.Address.ToString();
                        }
                    }

                    //IPv6
                    else if (Addfam == ADDRESSFAM.IPv6)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
                        {
                            output = ip.Address.ToString();
                        }
                    }
                }
            }
        }
        return output;
    }
}

public enum ADDRESSFAM
{
    IPv4, IPv6
}

【讨论】:

  • 我应该如何初始化NetworkManager?它给了我 NullReferenceException。正在尝试 NetworkManager networkManager = NetworkManager.singleton; NetworkManager networkManager = new NetworkManager();但是有新的错误,异常随着这一行而下降。
  • 您将NetworkManager 附加到游戏对象。如果您尚未将 NetworkManager 附加到 GameObject,那么您没有使用 uNet,应该在我的回答中使用第二种方法。
  • ALERT - 现在(2018 年末?)您似乎可以直接调用 nc.address
  • .. 虽然只在服务器上;您似乎无法在客户身上获得“自己的”。
  • @Fattie 嗨,它是在 2017.1 中添加的,甚至在我回答之前。使用它的问题在于你需要实现那些你用来获得它的功能。没有那些回调函数,你不能直接直接访问 ip 地址。这是我发现的唯一问题。
【解决方案2】:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

public class TestLocationService : MonoBehaviour
{
    public Text hintText;

    private void Start()
    {
        GetLocalIPAddress();
    }
    public string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                hintText.text = ip.ToString();
                return ip.ToString();
            }
        }
        throw new System.Exception("No network adapters with an IPv4 address in the system!");
    }

}

【讨论】:

    【解决方案3】:

    最终由 Unity 解决(从大约 2018.2 版本开始)

    在任何到达服务器的[Command] 内,

    发送[Command]的客户端IP是

            connectionToClient.address
    

    呼。


    您实际上将拥有自己的NetworkBehaviour 派生类,您必须这样做。 (通常称为“通讯”):

    public partial class Comms : NetworkBehaviour {
    

    该类必须覆盖服务器/客户端启动,以便每个 Comms “知道它是什么”。

    public override void OnStartServer() {
        .. this "Comms" does know it IS the server ..
    }
    
    public override void OnStartLocalPlayer() {
        .. this "Comms" does know it IS one of the clients ..
    }
    

    在任何实际项目中,由于 Unity 不这样做,因此客户端必须向服务器表明自己的身份。您必须从头开始在 Unity 网络中完全处理这些问题。

    (请注意,该过程在此处的长博客中进行了说明

    https://forum.unity.com/threads/networkmanager-error-server-client-disconnect-error-1.439245/#post-3754939)

    所以这是你(必须)在OnStartLocalPlayer做的第一件事

    public override void OnStartLocalPlayer() {
        
        Grid.commsLocalPlayer = this;
    
        StandardCodeYouMustHave_IdentifySelfToServer();
        
        // hundreds of other things to do..
        // hundreds of other things to do..
    }
    

    通讯中的“命令对”如下所示:

    您必须在所有网络项目中执行此操作(否则您将不知道哪个客户端是哪个客户端):

    public void StandardCodeYouMustHave_IdentifySelfToServer() {
        
        string identityString = "quarterback" "linebacker" "johnny smith"
            .. or whatever this device is ..
    
        CmdIdentifySelfToServer( identityString );
    
        // hundreds more lines of your code
        // hundreds more lines of your code
    }
    
    [Command]
    void CmdIdentifySelfToServer(string connectingClientIdString) {
        
        .. you now know this connection is a "connectingClientIdString"
        .. and Unity gives you the connection: in the property: connectionToClient
        .. you must record this in a hash, database, or whatever you like
    
        MakeANote( connectingClientIdString , connectionToClient )
    
        // hundreds more lines of your code
        // hundreds more lines of your code
    }
    

    好消息是Unity添加了connectionToClient属性,也就是说在服务器上,在[Command]里面。

    然后,您确实可以在其上使用新的.address 属性。

    你终于可以得到那个客户的IP了!

    public void StandardCodeYouMustHave_IdentifySelfToServer() {
        CmdIdentifySelfToServer( identityString );
    }
    
    [Command]
    void CmdIdentifySelfToServer(string connectingClientIdString) {
        MakeANote( connectingClientIdString , connectionToClient )
        string THEDAMNEDIP = connectionToClient.address;
    }
    

    就是那个“简单”,刚刚连接的客户端的ip就是“THEDAMNEDIP”。

    呼。

    只用了 Unity 5?年。

    【讨论】:

      【解决方案4】:

      2018 年……

      但是,请参阅下面的新答案。

      您现在似乎可以调用 - 在服务器上,在 NetworkManager 中 - 只需 NetworkConnection#address,它就会给您。

      回想一下,您必须编写自己的 NetworkManager,它不能开箱即用。如果您不熟悉统一网络,请在此处解释:

      https://forum.unity.com/threads/networkmanager-error-server-client-disconnect-error-1.439245/#post-3754939

      public class OurNetworkManager : NetworkManager {
      
          //
          // server .............
          //
      
          public override void OnServerConnect(NetworkConnection nc) {
      
              // it means "here on the server" one of the clients has connected
              base.OnServerConnect(nc);
      
              Log("a client connected " + nc.connectionId + " " + nc.hostId);
              Log("address? " + nc.address);
          }
      
          public override void OnServerDisconnect(NetworkConnection nc) { .. etc
      

      但请注意

      1) 这只会在服务器上提供给您

      2) 并且仅在“NetworkManager”中(当然!)实际上并不是在您识别每个连接的客户端时

      注意更新的答案 - Unity 终于解决了这个问题。

      【讨论】:

        【解决方案5】:

        这是对excellent answer already provided by @Programmer 的小修改。这里的动机是改进 MacOS 和 iOS 上的功能。我还没看过安卓。我也只测试过 IPV4。

        与@Programmer 的原作有何不同:

        1. 对于 MacOS 和 iOS,包括接口类型的过滤器
        2. .. 但排除对 OperationalStatus 的检查
        3. 将枚举移到类中
        4. 将类标记为静态
        5. 重构,所以有一种方法可以返回所有匹配的 IP,
          另一个简单地返回最后一个,它与原始版本的逻辑相匹配。
        6. 还包括一个用于 IP 列表的诊断选项,以包括一些详细信息,例如接口的“描述”(例如 en0en1)。如果您想要的只是 IP 地址本身,则显然不应使用此选项。
        public static class IPManager
        {
            public enum ADDRESSFAM
            {
                IPv4, IPv6
            }
        
            public static string GetIP(ADDRESSFAM Addfam)
            {
              string ret = "";
              List<string> IPs = GetAllIPs(Addfam, false);
              if (IPs.Count > 0) {
                ret = IPs[IPs.Count - 1];
              }
              return ret;
            }
        
            public static List<string> GetAllIPs(ADDRESSFAM Addfam, bool includeDetails)
            {
                //Return null if ADDRESSFAM is Ipv6 but Os does not support it
                if (Addfam == ADDRESSFAM.IPv6 && !Socket.OSSupportsIPv6)
                {
                    return null;
                }
        
                List<string> output = new List<string>();
        
                foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
                {
        
        #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IOS
                    NetworkInterfaceType _type1 = NetworkInterfaceType.Wireless80211;
                    NetworkInterfaceType _type2 = NetworkInterfaceType.Ethernet;
        
                    bool isCandidate = (item.NetworkInterfaceType == _type1 || item.NetworkInterfaceType == _type2);
        
        #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
                    // as of MacOS (10.13) and iOS (12.1), OperationalStatus seems to be always "Unknown".
                    isCandidate = isCandidate && item.OperationalStatus == OperationalStatus.Up;
        #endif
        
                    if (isCandidate)
        #endif 
                    {
                        foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
                        {
                            //IPv4
                            if (Addfam == ADDRESSFAM.IPv4)
                            {
                                if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                                {
                                    string s = ip.Address.ToString();
                                    if (includeDetails) {
                                        s += "  " + item.Description.PadLeft(6) + item.NetworkInterfaceType.ToString().PadLeft(10);
                                    }
                                    output.Add(s);
                                }
                            }
        
                            //IPv6
                            else if (Addfam == ADDRESSFAM.IPv6)
                            {
                                if (ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
                                {
                                    output.Add(ip.Address.ToString());
                                }
                            }
                        }
                    }
                }
                return output;
            }
        }
        

        【讨论】:

          【解决方案6】:
          using UnityEngine;
          using System.Collections;
          using System.Net;
          using System.Net.NetworkInformation;
          using System.Net.Sockets;
          using System;
          using UnityEngine.Networking;
          using Newtonsoft.Json;
          
          public class geoplugin
          {
              //Assume E.g. before each comment
              public string geoplugin_request; //THIS IS THE IP ADDRESS
              public int geoplugin_status; //200
              public string geoplugin_delay; //"1ms"
              public string geoplugin_credit;
              public string geoplugin_city; //E.g Toronto. 
              public string geoplugin_region; //E.g. Ontario
              public string geoplugin_regionCode; //E.g. ON
              public string geoplugin_regionName; //Also Ontario
              public string geoplugin_areaCode; //idk
              public string geoplugin_dmaCode; //idk
              public string geoplugin_countryCode; //E.g. CA (that's Canada)
              public string geoplugin_countryName; //E.g. Canada
              public int geoplugin_inEU; //0 if not in EU
              public bool geoplugin_euVATrate; //false
              public string geoplugin_continentCode; //E.g. NA
              public string geoplugin_continentName; //North America
              public string geoplugin_latitude; 
              public string geoplugin_longitude; 
              public string geoplugin_locationAccuracyRadius; //"1"
              public string geoplugin_timezone; //"America\/Toronto",
              public string geoplugin_currencyCode; //"CAD",
              public string geoplugin_currencySymbol; //"$",
              public string geoplugin_currencySymbol_UTF8; //$",
              public float geoplugin_currencyConverter;
          }
          
          public class GetMyIP : MonoBehaviour 
          {
              geoplugin geoInfo;
              string ip;
          
          
              public void GetIP()
              {
                  StartCoroutine(GetRequest("http://www.geoplugin.net/json.gp", (UnityWebRequest req) =>
                  {
                      if (req.isNetworkError || req.isHttpError)
                      {
                          Debug.Log($"{req.error}: {req.downloadHandler.text}");
                      }
                      else
                      {
                          geoplugin geopluginData = JsonConvert.DeserializeObject<geoplugin>(req.downloadHandler.text);
          
                          ip = geopluginData.geoplugin_request;
                          geoInfo = geopluginData;
                          Debug.Log(ip);
          
                          //AT THIS POINT IN THE CODE YOU CAN DO WHATEVER YOU WANT WITH THE IP ADDRESS
                      }
                  }));
              }
          
              IEnumerator GetRequest(string endpoint, Action<UnityWebRequest> callback)
              {
                  using (UnityWebRequest request = UnityWebRequest.Get(endpoint))
                  {
                      // Send the request and wait for a response
                      yield return request.SendWebRequest();
          
                      callback(request);
                  }
              }
          }
          

          这应该为您提供存储在字符串ip 中的 IP 地址,您可以随意使用它。这也有可能会为您提供大量信息,而这些信息首先需要 IP 地址。

          这就是我的经验。我试图创建一个与真实世界天气相匹配的游戏天气系统,并且我希望通过 IP 地址找到位置,但本网站提供了两者,无需先获取 IP 地址。

          这是我找出这段代码的教程:https://theslidefactory.com/using-unitywebrequest-to-download-resources-in-unity/

          您还需要导入此代码才能正常工作:https://assetstore.unity.com/packages/tools/input-management/json-net-for-unity-11347

          如果您只想要 IP 地址而不需要其他任何东西,那么这不是最佳解决方案。但是,大多数时候,您想对 IP 地址做一些事情,例如获取位置,这提供了很多您可能试图获取的东西。

          【讨论】:

            【解决方案7】:

            https://stackoverflow.com/a/67450052/18192881

            关于 geofilter 数据帖子,根据他们的条款: “限制。 一般的。您不得,也不得允许他人:

            ix:将服务用于识别或定位特定个人或家庭。”

            所以我不会依赖他们,因为它是“非法的?”或至少违反他们的政策。

            【讨论】:

              猜你喜欢
              • 2013-06-29
              • 2015-02-26
              • 2021-04-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-02-09
              • 1970-01-01
              • 2016-10-23
              相关资源
              最近更新 更多