Unity .Net 2.0 UPNP端口映射

时间:2016-11-02 17:19:52

标签: networking unity3d mono .net-2.0 upnp

我最近一直在尝试为我的游戏设置端口映射。这是为了让其中一名球员成为主持人。为此,我需要播放器打开端口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);
}

我调用的最后一个调试语句是数字4.我没有打开端口,也没有抛出任何异常。 我做错了什么?

另外,在我的开始功能中,我称之为:

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

1 个答案:

答案 0 :(得分:1)

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

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

  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版本:

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