无第三方服务器的UDP打洞难度大,如何借助第三方实现UDP Hole Punching?
Great question—this is a common pain point when dealing with NAT traversal. Let's break down exactly how to implement UDP hole punching with a third-party relay server, using concrete examples to make it clear.
We’ll use two peers (PeerA and PeerB, both behind separate NATs) and a public relay server with a known public IP/port (let’s say 1.2.3.4:9000) for this walkthrough.
Step 1: Peers Register with the Relay Server
First, each peer sends a UDP packet to the relay server to announce their presence:
- PeerA is on local IP
192.168.1.100:7777. When this packet hits their NAT, the NAT translates it to a public IP/port pair—let’s say203.0.113.5:55123(the port is randomly assigned by the NAT). - The relay server receives this packet, records PeerA’s public endpoint (
203.0.113.5:55123) along with any identifier PeerA sent (like a username or unique ID). - PeerB does the same: their local
10.0.0.5:8888gets translated to public198.51.100.20:66456by their NAT, and the relay server stores this endpoint too.
Step 2: Relay Server Exchanges Peer Endpoints
Once both peers are registered, the relay server shares each peer’s public endpoint with the other:
- It sends a UDP packet to PeerA’s public endpoint (
203.0.113.5:55123) containing PeerB’s public info:198.51.100.20:66456. - It sends a matching packet to PeerB’s public endpoint (
198.51.100.20:66456) with PeerA’s public details.
Step 3: Peers Send "Hole Punch" Packets
This is the critical step—immediately after receiving the other peer’s endpoint, each peer sends a UDP packet directly to that public address:
- PeerA sends a packet to
198.51.100.20:66456. Since PeerA’s NAT already has an open mapping from their local port to203.0.113.5:55123(from Step 1), this outgoing packet tells the NAT to allow incoming traffic from PeerB’s public IP/port to reach PeerA’s local192.168.1.100:7777. - PeerB does the exact same: sends a packet to
203.0.113.5:55123. Their NAT adds a similar entry, allowing incoming traffic from PeerA’s public endpoint.
Step 4: Establish Direct Peer-to-Peer Connection
Even if the first "hole punch" packet gets dropped by the receiving NAT (a common edge case), subsequent packets will work. Once both NATs have the incoming traffic rules in place, the peers can send UDP packets directly to each other’s public endpoints, and the NATs will route them to the local peers.
Key Tips for Success:
- Timing matters: Send the hole punch packets right after getting the peer’s endpoint—if too much time passes, the NAT might close the initial mapping from Step 1.
- Strict NATs need mutual punching: Some NATs only allow incoming traffic from the exact IP/port the peer sent to initially. This is why both peers must send the hole punch packet—so each NAT explicitly allows the other’s traffic.
- Relay server is only for setup: Once the hole is punched, peers communicate directly without relying on the relay server anymore.
Example Recap:
PeerA’s NAT translates local192.168.1.100:7777to public203.0.113.5:55123when sending to the relay. The server shares PeerB’s endpoint with PeerA. PeerA sends a packet to PeerB’s public port, which tells their NAT to allow PeerB’s incoming traffic. PeerB does the same, and direct UDP communication is now possible.
内容的提问来源于stack exchange,提问作者Basj

