Sockets 需要帮助为p2p数据传输设置udp打孔。Can';I don’我工作时不会晕眩

Sockets 需要帮助为p2p数据传输设置udp打孔。Can';I don’我工作时不会晕眩,sockets,udp,p2p,hole-punching,Sockets,Udp,P2p,Hole Punching,我正在尝试将UDP数据包从一个客户端发送到另一个客户端。让C1成为我用来接收数据的客户端,C2成为发送数据的客户端。我在做什么: 向STUN服务器询问两个客户端的公共IP地址和端口 我将其他IP地址和公共端口通知每个客户机 C1向其公共地址和端口上的C2发送数据包,并开始侦听数据包。同时,C2开始发送包含我想要传输的数据的数据包 C1只是挂起接收一个永远不会到达的数据包。我把球打错了吗 我正在对同一网络上同一台计算机上的两个客户端进行测试,但服务器位于另一个具有公共IP的网络上的服务器上。我想说

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

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

  • 我将其他IP地址和公共端口通知每个客户机

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

  • C1只是挂起接收一个永远不会到达的数据包。我把球打错了吗

    我正在对同一网络上同一台计算机上的两个客户端进行测试,但服务器位于另一个具有公共IP的网络上的服务器上。我想说的是,当我测试时,两个客户的公共广播是相同的,这是一个问题吗

    更新:

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

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

    更新2:

    在@Tahlil的帮助下,我发现我用来检查NAT类型的算法有缺陷,我试图在对称NAT后面打孔。所以问题是没有注意到我的代码有错误。。。我建议所有面临相同问题的人都明确地断言NAT类型


    谢谢大家的帮助。

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

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

    但我认为在您的场景中,数据包不会离开NAT,因为它们都在同一个网络下。这就是NAT不创建任何映射的原因。所以你的打孔失败了

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

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

    编辑:

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


    不要为了打孔而向另一端发送垃圾邮件。如果你的IP上充斥着数据包,NAT会阻止你的IP。从一侧打孔,TTL值低。因此,用于穿孔的数据包离开NAT,但不会到达另一个NAT。这样,打孔将成功完成,另一侧NAT不会被淹没。试着从另一侧晚一点发送数据包,以便从另一侧完成打孔。当穿孔侧收到第一个数据包时,停止穿孔并开始正常发送数据包。

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

    此外,如果C1和C2位于同一子网上,则您的NAT可能不允许发夹。“发夹”是指通过外部地址向内部发送邮件的能力。并非所有NAT都支持这一点。准备好尝试连接内部候选地址以及STUN发现的外部地址

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


    谢谢您的awnser Tahlil。这是为了与不同NAT后面的客户端一起使用,但我正在用同一网络上的计算机进行测试,因为这就是我所拥有的。我要做一些测试,记住你告诉我的(我正在尝试在不同的网络中设置两台计算机),然后我会发布结果。请记住,C2需要在C1打孔完成后开始发送数据包。否则C1将不会收到任何东西,因为C2将被NAT阻止。好的,我不知道实际上。。。这可能是导致数据包被丢弃的另一个原因。谢谢你,所以我在另一台NAT后面用了第二台电脑,但还是不行。。。我发布了我用来尝试udp打孔的代码。请看一看,如果你能。。。我真的不明白我可能做错了什么。再次感谢您的支持(阿恩瑟:)我知道两个NAT都是全锥形的。我会用你在编辑中给我的建议再试一次。谢谢你的帮助谢谢你的awnser selbie,我在描述上有一个错误,它是挂起的C1,尽管它已经发送了第一个数据包(很抱歉,我编辑了它)。我以前读过你的awnser,事实上它帮助我理解了这一切是如何运作的;)。我还用tcp来协调所有事情,以确保事情按照所需的顺序发生。我将尝试在不同的网络中设置两台计算机,看看这是否是因为NAT不允许发夹。再次感谢。TCP nat遍历的难度是UDP nat遍历的两倍。在TCP中,您可能需要让两个端点同时使用重试逻辑相互连接。仍然无法。。。我知道在我的路由器上进行发夹是可能的,因为如果我进行端口转发,并使用它们通过的公共地址将数据包从一个客户端发送到另一个客户端。我写了一些
    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");
                }
            }
        }