java 如何打洞
在 Java 中实现 NAT 穿透(“打洞”)通常需要结合 UDP 协议和特定技术(如 STUN、TURN 或 ICE)。以下是关键实现方法:

使用 STUN 协议
STUN(Session Traversal Utilities for NAT)用于发现 NAT 类型和获取公网地址。Java 可通过 jstun 库实现:

import de.javawi.jstun.attribute.*;
import de.javawi.jstun.header.*;
import de.javawi.jstun.util.*;
import java.net.*;
// 创建 STUN 客户端
InetAddress stunServer = InetAddress.getByName("stun.l.google.com");
MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
byte[] data = sendMH.getBytes();
DatagramPacket send = new DatagramPacket(data, data.length, stunServer, 19302);
// 发送请求并接收响应
DatagramSocket s = new DatagramSocket();
s.send(send);
byte[] buf = new byte[512];
DatagramPacket recv = new DatagramPacket(buf, buf.length);
s.receive(recv);
UDP 打洞实现
直接 UDP 打洞需要两端同时向对方发送数据包以建立连接:
// 客户端A代码(已知客户端B的公网IP和端口)
DatagramSocket socketA = new DatagramSocket(localPortA);
InetAddress publicIPB = InetAddress.getByName("B的公网IP");
socketA.send(new DatagramPacket(new byte[1], 1, publicIPB, portB));
// 客户端B代码(已知客户端A的公网IP和端口)
DatagramSocket socketB = new DatagramSocket(localPortB);
InetAddress publicIPA = InetAddress.getByName("A的公网IP");
socketB.send(new DatagramPacket(new byte[1], 1, publicIPA, portA));
使用 ICE 框架
ICE(Interactive Connectivity Establishment)整合 STUN/TURN,推荐使用 ice4j 库:
import org.ice4j.ice.*;
import org.ice4j.ice.harvest.StunCandidateHarvester;
// 创建 ICE Agent
Agent agent = new Agent();
agent.addCandidateHarvester(new StunCandidateHarvester(
new TransportAddress("stun.l.google.com", 19302, Transport.UDP)));
// 收集候选地址并协商连接
agent.startConnectivityEstablishment();
注意事项
- 对称型 NAT 难以穿透,需依赖 TURN 服务器中转
- 保持心跳包维持 NAT 映射表有效期
- 生产环境建议使用成熟库如 WebRTC 或 Pion(Java 可通过 JNI 调用)
以上方法可根据具体网络环境组合使用,建议先通过 STUN 检测 NAT 类型再选择对应策略。






