如何在 Unity 中获取网络中的所有设备?

至少视觉

现在已经有大约 8 个小时了,我正在尝试找到一种方法,以便我可以接收与我在同一网络中的所有设备。我已经找到了几种方法来做到这一点,但所有这些都归结为 ping 网络中的所有 IP。如果 Unity 允许多线程,那不会是一个大问题。由于它不/基本上只允许 IEnumerator 我有一个问题,我必须一个接一个地执行每个 ping,这需要很多时间,你甚至不能使用 GUI。

我当前的代码如下所示:

public class AddressFinder {

    private List<Ping> pingers = new List<Ping>();
    private List<IPAddress> addresses = new List<IPAddress>();

    private int timeOut = 250;
    private int ttl = 5;
    private int instances;
    private MonoBehaviour m;

    public void Scan(MonoBehaviour mono, IPSegment ips, Action<List<IPAddress>> callback) {
        this.m = mono;
        m.StartCoroutine(ScanAsync(ips, callback)); // New Coroutine so the UI should not freeze
    }

    private IEnumerator ScanAsync(IPSegment ips, Action<List<IPAddress>> callback) {
        PingOptions po = new PingOptions(ttl, true);
        byte[] data = new System.Text.ASCIIEncoding().GetBytes("abababababababababababababababab");
        instances = 0;
        foreach(uint host in ips.Hosts()) {  // Itterate through all IPs in that network
            m.StartCoroutine(Send(IPHelper.ToIpString(host) // IP as String, data, po));
        }
        WaitForSeconds wait = new WaitForSeconds(0.05f);
        while(instances > 0) {
            yield return wait;
        }
        callback(addresses);
    }

    private IEnumerator Send(string ip, byte[] data, PingOptions po) {
        instances++;
        Ping p = new Ping();
        PingReply rep = p.Send(ip, timeOut, data, po);
        p.Dispose();
        if(rep.Status == IPStatus.Success)
            addresses.Add(IPAddress.Parse(ip));
        instances--;
        yield return new WaitForSeconds(0);
    }
}

这个 wcode 实际上可以工作,但需要 4 分钟来测试我网络中的所有 253 个 IP。在此期间 UI 也会冻结。

我还尝试使用统一 Ping,它看起来非常不一致,而且效果也不好,因为它也需要很多 254 个 ping。

有没有人知道问题是什么或有其他想法让网络中的所有设备?

至少视觉

我找到了线程的方法。我实际上认为不应在 Unity 中使用线程,但似乎只是不在主线程之外使用 Unity 操作,这意味着允许其他线程。无论如何,这是我的代码:

using Ping = System.Net.NetworkInformation.Ping;

public class AddressFinder {

    public List<string> addresses = new List<string>();
    private MonoBehaviour m;

    Thread myThread = null;
    public int instances = 0;

    public AddressFinder(MonoBehaviour mono) {
        m = mono;
    }

    public void Scan(List<IPSegment> iPSegments, Action<List<string>> addresses) {
        myThread = new Thread(() => ScanThreads(iPSegments, addresses));
        myThread.Start();
    }

    private void ScanThreads(List<IPSegment> iPSegments, Action<List<string>> callback) {
        Ping myPing;
        PingReply reply;
        instances = 0;

        foreach(IPSegment ips in iPSegments) {
            foreach(uint hosta in ips.Hosts()) {
                string ip = IPHelper.ToIpString(hosta);
                Task.Factory.StartNew(() => {
                    myPing = new Ping();
                    instances++;
                    reply = myPing.Send(ip, 250);

                    if(reply.Status == IPStatus.Success) {
                        addresses.Add(ip);
                    }
                    instances--;
                }, TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning);
            }
        }
        int i = 0;
        while(instances > 0) {
            if(i > 100)
                break;
            i++;
            Thread.Sleep(10);
        }
        callback(addresses);
    }
}
public class LobbyManager : MonoBehaviour {

    public UnityEngine.Object[] Games;
    private List<string> localAddresses = new List<string>();
    private List<string> hostAddresses = new List<string>();
    private Ping p;
    AddressFinder af;

    public void Start() {
        List<IPSegment> iPSegments = GetInterfaces(true);
        af = new AddressFinder(this);
        af.Scan(
            iPSegments,
            (addresses) => {
                localAddresses = addresses;
                foreach(string address in localAddresses) {
                    Debug.Log(address.ToString());
                }
            }
        );
    }

    public void Update() {

    }

    public List<IPSegment> GetInterfaces(bool showVPN) {
        List<IPSegment> ipsList = new List<IPSegment>();
        foreach(NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) {
            if(ni.Name.Contains("VM") || ni.Name.Contains("Loopback"))
                continue;
            if(!showVPN && ni.Name.Contains("VPN"))
                continue;
            foreach(UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) {
                if(ip.Address.AddressFamily == AddressFamily.InterNetwork) {
                    IPSegment ips = new IPSegment(ip.Address.ToString(), ip.IPv4Mask.ToString());
                    ipsList.Add(ips);
                }
            }
        }
        return ipsList;
    }
}

IPSegment是一个类,其中根据子网掩码保存了该段中的所有 IP。

这段代码工作得很好,但不是那么高效,这意味着子网掩码不应高于 255.255.255.0,否则需要时间。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章