繁体   English   中英

需要帮助设置udp打孔以进行p2p数据传输。 无法使STUN工作

[英]Need help setting udp hole punching for p2p data transfer. Can't get STUN to work

我正在尝试将UDP数据包从一个客户端发送到另一个客户端。 C1为我要用来接收数据的客户端,让C2为要发送数据的客户端。 我在做什么:

  1. 向STUN服务器询问两个客户端的公共IP地址和端口。

  2. 我将其他IP地址和公共端口告知每个客户端。

  3. C1在其公共地址和端口上向C2发送一个数据包,并开始侦听数据包。 同时, C2开始发送包含我要传输的数据的数据包。

C1只是挂在收到永不到达的数据包上。 我在做UDP孔打孔错误吗?

我正在使用同一网络中同一台计算机上的两个客户端测试此服务器,但是该服务器位于具有公共IP的另一个网络中的服务器上。 我要说的是,在我测试时,两个客户的公共地址都相同,这是一个问题吗?

更新:

我现在知道路由器允许发夹。 我在路由器上转发了UDP端口,并使用公共IP地址可以将数据包从一个客户端发送到另一个客户端。

这是我用来测试是否可以在C#中打孔的代码:

static UdpClient udpClient = new UdpClient(30001);
static IPAddress remoteIp;
static int remotePort;

static void Main(string[] args)
{
        // Send packet to server so it can find the client's public address and port 
        byte[] queryServer = Encoding.UTF8.GetBytes("something");
        udpClient.Send(testMsg, testMsg.Length, new IPEndPoint(IPAddress.Parse("199.254.173.154"), 30000));

        // Wait for a response from the server with the other client's public address and port
        IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);           
        byte[] dataJsonBytes = udpClient.Receive(ref sender);
        JObject json = JObject.Parse(Encoding.UTF8.GetString(dataJsonBytes));
        remoteIp = IPAddress.Parse(json["IP"].ToString());
        remotePort = Int32.Parse(json["port"].ToString());                                                    

        // Start spamming the other client with packets and waiting for response
        Thread sendingThread = new Thread(sendPacket);
        Thread receivingThread = new Thread(receivePacket);

        sendingThread.Start();
        receivingThread.Start();

        Console.ReadLine();
    }

    private static void sendPacket()
    {
        byte[] udpMessage = Encoding.UTF8.GetBytes("Forcing udp hole punching!!\n");
        while (true)
        {               
            udpClient.Send(udpMessage, udpMessage.Length, new IPEndPoint(remoteIp, remotePort));
            Thread.Sleep(100);
        }
    }

    private static void receivePacket()
    {
        IPEndPoint senderEp = new IPEndPoint(IPAddress.Any, 0);
        udpClient.Client.ReceiveTimeout = 500;
        while (true)
        {
            try
            {
                byte[] receivedData = udpClient.Receive(ref senderEp);
                Console.Write(Encoding.UTF8.GetString(receivedData));
            }
            catch (Exception)
            {
                Console.Write("Timeout!!\n");
            }
        }
    }

更新2:

在@Tahlil的帮助下,我能够确定用于检查NAT类型的算法存在缺陷,并且试图在对称NAT后面进行打孔。 因此问题并没有在我的代码上引起错误……我建议对所有面临相同问题的人断言NAT类型。

谢谢大家的帮助。

当然C2将挂起。 因为C2 NAT可能在C2发送数据包之前拒绝了C1发送的原始数据包。 在所有这些中建立一些重试逻辑以克服这些问题。

另外,如果C1和C2在同一子网上,则您的NAT可能不允许发夹。 “发夹”是通过您的外部地址内部发送的功能。 并非所有NAT都支持此功能。 准备尝试同时连接内部候选地址和STUN发现的外部地址。

无论如何,从我之前给出的答案开始。

https://stackoverflow.com/a/8524609/104458

某些NAT不允许来自未知来源的数据包。 这就是为什么我们在NAT中打孔,以便NAT可以识别该未知IP并为其创建映射。

如果C1和C2在不同的网络中。 然后,如果C2将数据包发送到C1的公共IP:端口,则C2的NAT将为C1的公共IP:端口创建映射。 之后,来自C2的公共IP:Port中C1的任何数据都将转发到C2。

但是我认为在您的情况下,数据包没有离开NAT,因为它们都在同一网络下。 这就是为什么NA​​T不创建任何映射的原因。 因此,打孔失败。

因此,当您从C1向C2的公共IP地址发送数据时,您假设到那时C2已为C1的地址打了一个洞,而NAT已创建了映射。 但是C2的打孔失败,因为C1在同一网络中。

如果您在同一网络中,为什么还需要打孔? 这是一个奇怪的意图,因为C1和C2可以直接向彼此的私有IP发送数据包并建立连接。 当C1和C2在不同的网络中时,需要打孔。

编辑:

如果两个客户端的NAT组合类似于对称与对称,则打孔将不起作用。 因此,首先检查两端的NAT类型是什么。

不要用小包向另一端发送垃圾邮件,以免打孔。 如果用数据包淹没,NAT可以阻止您的IP。 从一侧打孔且TTL值低。 这样,用于打孔的数据包会离开NAT,但不会到达另一个NAT。 这样,打孔将成功完成,并且不会淹没另一侧的NAT。 从另一侧尝试将数据包稍晚发送,以便从另一侧完成打孔。 当打孔侧收到第一个数据包时,请停止打孔并正常开始发送数据包。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM