Unity .Net 2.0 UPNP端口映射

Unity .Net 2.0 UPNP Port Mapping

我最近一直在尝试为我的游戏设置端口映射。这是为了让其中一位玩家成为主持人。为此,我需要播放器打开端口 7777。

如果已有匹配项,它将直接加入。如果它没有找到空的匹配项,它就会简单地匹配一个。如果它没有成功,它会等到有人做出来并加入它。

因此我需要能够使用 UPnP 之类的东西来映射我的端口。我还需要能够捕获错误,以查看是继续创建匹配项还是简单地等待一个匹配项并加入。

我目前正在使用 .NET 2.0 的 Unity 游戏引擎工作。这让我非常有限,因为 Open.NAT 不兼容。我尝试了 Mono.NAT,但无法正常工作。

有没有人对我应该如何处理这个问题有任何建议?使用哪些库,甚至可能为我提供代码片段以帮助我入门。

谢谢,TwoTen。

Edit1:当前的 Mono.NAT 代码如下所示:

private void DeviceFound(object sender, DeviceEventArgs args)
{
    Debug.Log("1");
    INatDevice device = args.Device;
    Debug.Log("2");
    Mapping map = new Mapping(Protocol.Tcp, 6699, 6699);
    Debug.Log("3");
    device.CreatePortMap(map);
    Debug.Log("4");
    int test = device.GetAllMappings().Length;
    Debug.Log(test);
    foreach (Mapping portMap in device.GetAllMappings())
    {
        Debug.Log("5");
        Debug.Log(portMap.ToString());
    }
}
private void DeviceLost(object sender, DeviceEventArgs args)
{
    INatDevice device = args.Device;
    Mapping map = new Mapping(Protocol.Tcp, 6699, 6699);
    device.DeletePortMap(map);
}

I 最后调用的调试语句是 4。I 端口没有打开,也没有抛出异常。 我做错了什么?

此外,在我的启动函数中,我调用这个:

NatUtility.DeviceFound += DeviceFound;
NatUtility.DeviceLost += DeviceLost;
NatUtility.StartDiscovery();

我找到了如何成功的答案。我放弃了 Mono.NAT,而是使用 Open.NAT,它已移植到与 Unity 兼容的 .NET 3.5!

我最终使用的最终代码如下所示:

  private static Task Test()
{
    var nat = new NatDiscoverer();
    var cts = new CancellationTokenSource();
    cts.CancelAfter(5000);

    NatDevice device = null;
    var sb = new StringBuilder();
    IPAddress ip = null;

    return nat.DiscoverDeviceAsync(PortMapper.Upnp, cts)
        .ContinueWith(task =>
        {
            device = task.Result;
            return device.GetExternalIPAsync();

        })
        .Unwrap()
        .ContinueWith(task =>
        {
            ip = task.Result;
            sb.AppendFormat("\nYour IP: {0}", ip);
            return device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 7777, 7777, 0, "myGame Server (TCP)"));
        })
        .Unwrap()
        .ContinueWith(task =>
        {
            return device.CreatePortMapAsync(
                new Mapping(Protocol.Udp, 7777, 7777, 0, "myGame Server (UDP)"));
        })
        .Unwrap()
        .ContinueWith(task =>
        {
            sb.AppendFormat("\nAdded mapping: {0}:1700 -> 127.0.0.1:1600\n", ip);
            sb.AppendFormat("\n+------+-------------------------------+--------------------------------+------------------------------------+-------------------------+");
            sb.AppendFormat("\n| PORT | PUBLIC (Reacheable)           | PRIVATE (Your computer)        | Description                        |                         |");
            sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
            sb.AppendFormat("\n|      | IP Address           | Port   | IP Address            | Port   |                                    | Expires                 |");
            sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
            return device.GetAllMappingsAsync();
        })
        .Unwrap()
        .ContinueWith(task =>
        {
            foreach (var mapping in task.Result)
            {
                sb.AppendFormat("\n|  {5} | {0,-20} | {1,6} | {2,-21} | {3,6} | {4,-35}|{6,25}|",
                    ip, mapping.PublicPort, mapping.PrivateIP, mapping.PrivatePort, mapping.Description,
                    mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP", mapping.Expiration.ToLocalTime());
            }
            sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
            sb.AppendFormat("\n[Removing TCP mapping] {0}:1700 -> 127.0.0.1:1600", ip);
            return device.DeletePortMapAsync(new Mapping(Protocol.Tcp, 1600, 1700));
        })
        .Unwrap()
        .ContinueWith(task =>
        {
            sb.AppendFormat("\n[Done]");
            Debug.Log(sb.ToString());
        });
}

我所要做的就是在启动函数中执行此操作:

Test().Wait();

路由器注册端口并打开。然而。网站 canyouseeme.org 出于某种原因未能将端口视为打开状态。为了验证它是否已注册,我进入路由器设置并查找 UPnP。然后有一个应用程序列表,包括我的。我还没有进行真实世界的测试,但一旦完成,我会更新 post。

在此处找到与 Unity 兼容的 Open.NAT 版本:

编辑:我现在已经进行了真实世界的测试。一切正常,用户可以在没有中继和/或统一配对服务器的情况下进行连接