【问题标题】:Unity .Net 2.0 UPNP Port MappingUnity .Net 2.0 UPNP 端口映射
【发布时间】:2016-11-02 17:19:52
【问题描述】:

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

如果已经有匹配,它会简单地加入它。如果它没有找到空匹配,它将简单地创建一个。如果它无法制作一个,它将等到有人制作一个并加入它。

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

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

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

谢谢,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,但我无法让它工作"请将代码发布到那里。这对我有用。我需要看看你在做什么。另外,你怎么知道它不起作用?
  • 我更新了帖子以包含我的代码。
  • Debug.Log(test); 替换Debug.Log("4++"+test); 然后再次使用日志更新问题。另外,你把 Mono.NAT DLL 放在哪里了?
  • 我的 mono.nat dll 在我的 Asset 文件夹中。 Debug.Log("4++" + test) 永远不会被调用。只有 1、2、3 和 4 被跟注。目前我正在使用 CanYouSeeMe.org 来验证端口是否已正确添加。
  • 这似乎是对的。您的代码正是我正在使用的。 NAT 的问题是启动它在某些路由器上有效,而在其他路由器上无效。有时,由于防火墙,它不起作用,有时它不起作用,因为您的路由器上禁用了 UPNP。确保您的编辑器没有防火墙阻止它。此外,如果您可以访问您的路由器,请登录并检查 UPNP 是否已禁用。

标签: networking unity3d mono .net-2.0 upnp


【解决方案1】:

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

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

  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。然后有一个应用程序列表,包括我的。我还没有进行真实世界的测试,但一旦完成,我会更新帖子。

这里找到了与 Unity 兼容的 Open.NAT 版本:

编辑:我现在已经进行了真实世界的测试。一切正常,用户无需中继和/或统一匹配服务器即可连接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 2014-08-21
    • 2014-05-04
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多