如何在Unity 2018+中获取设备的IP地址?

时间:2018-08-22 22:06:16

标签: c# unity3d ip ip-address

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

似乎Network.player.ipAddress现在已不推荐使用,所以我正在寻找一种新方法。

6 个答案:

答案 0 :(得分:6)

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

如果您正在使用Unity的新uNet网络系统,则可以使用NetworkManager.networkAddress;

string IP = NetworkManager.singleton.networkAddress;

如果您使用的是原始网络协议和TCP / UDP等API,则必须使用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
}

答案 1 :(得分:2)

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

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

发送[Command]的客户端的IP是

        connectionToClient.address

Ph。


实际上,您将拥有自己的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”。

Ph。

仅使用Unity 5?年。

答案 2 :(得分:1)

对于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终于解决了这个问题。

答案 3 :(得分:0)

这是对excellent answer already provided by @Programmer的较小修改。这样做的动机是为了改善MacOS和iOS上的功能。我还没有看过android。我也只测试了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;
    }
}

答案 4 :(得分:0)

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!");
    }

}

答案 5 :(得分:0)

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 地址执行某些操作,例如获取位置,这提供了您可能想要获取的许多内容。