我试图在Java中实现UDP-Holepunching的简单草图以测试其概念,并稍后在我的C / C ++应用程序中使用它。
从Wikipedia来说,我的理解是:A和B是未定义网络结构背后的客户端,C是著名的公共可访问服务器。
这在localhost上都运行良好(这并不奇怪),但是在实际示例中,此操作失败。
A和B都可以连接到服务器C,服务器C获取其数据包,存储其地址和端口,并将其传输到另一个客户端。但是在这一点上它失败了。A和B无法互相通信。所以我问自己我做错了什么。我花了几天时间在google和stackoverflow中搜索工作示例,但我偶然发现的是使用STUN的建议,这不是我想要的。
下面,我将用Java发布我的草图,因为我不知道我的概念或实现是否有问题。
public class Server
{
public static void main(String[] args)
{
int port1 = 0, port2 = 0;
String address1 = null, address2;
byte[] bytes = new byte[1024];
try
{
System.out.println("Server waiting");
DatagramSocket ds = new DatagramSocket(789);
while(!Thread.interrupted())
{
DatagramPacket p = new DatagramPacket(bytes, bytes.length);
ds.receive(p);
if(port1 == 0)
{
port1 = p.getPort();
address1 = p.getAddress().getHostAddress();
System.out.println("(1st) Server received:" + new String(bytes) + " from " + address1 + " on port " + port1);
}
else
{
port2 = p.getPort();
address2 = p.getAddress().getHostAddress();
System.out.println("(2nd) Server received:" + new String(bytes) + " from " + address1 + " on port " + port1);
sendConnDataTo(address1, port1, address2, port2, ds);
sendConnDataTo(address2, port2, address1, port1, ds);
}
}
ds.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void sendConnDataTo(String a1, int p1, String a2, int p2, DatagramSocket ds)
{
byte[] bA, bP;
bA = a1.getBytes();
bP = Integer.toString(p1).getBytes();
DatagramPacket pck;
try
{
pck = new DatagramPacket(bA, bA.length, InetAddress.getByName(a2), p2);
ds.send(pck);
pck = new DatagramPacket(bP, bP.length, InetAddress.getByName(a2), p2);
ds.send(pck);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
请注意,这只是一些草图,没有实际应用。服务器应该只从两个客户端接收数据包,保存它们的地址和端口,然后将其传递给另一个客户端。
public class Client
{
private DatagramSocket socket;
private int init = 0;
private String target;
private int port;
public Client()
{
try
{
socket = new DatagramSocket();
}
catch(SocketException e)
{
e.printStackTrace();
}
Thread in = new Thread()
{
public void run()
{
while(true)
{
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
try
{
socket.receive(packet);
bytes = Arrays.copyOfRange(bytes, 0, packet.getLength());
String s = new String(bytes);
System.out.println("Received: " + s);
if(init == 0)
{
target = s;
System.out.println("Target: " + target);
init++;
}
else if(init == 1)
{
port = Integer.parseInt(s);
System.out.println("Port: " + port);
init++;
}
else System.out.println(new String(bytes));
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
};
in.start();
connectToSupervisor();
}
private void connectToSupervisor()
{
byte[] bytes = new byte[1024];
System.out.println("Greeting server");
System.arraycopy("EHLO".getBytes(), 0, bytes, 0, 4);
try
{
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 789);
socket.send(packet);
System.out.println("Greetings sent...");
}
catch(IOException e)
{
e.printStackTrace();
}
send();
}
private void send()
{
while(init != 2)
{
try
{
Thread.sleep(20L);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("Init completed!");
while(true)
{
byte[] b2 = "Hello".getBytes();
byte[] b1 = new byte[6];
System.arraycopy(b2, 0, b1, 0, b2.length);
try
{
DatagramPacket packet = new DatagramPacket(b1, b1.length, InetAddress.getByName(target), port);
socket.send(packet);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
new Client();
}
}
客户端将只是向服务器发送一个数据包,侦听来自它的数据包,从另一个客户端获取连接数据,然后将持续向其发送包含“ Hello”的数据包。
很长的代码,我很抱歉,但是我想保持完整。
如果你们中的任何人都可以指出我在做的错误,向我解释为什么这没有用,给我一个有效的例子,或者至少指出一个替代方案,我将很高兴。
您的代码似乎是正确的。我测试了您的代码,效果很好。这个概念也是正确的。但是,请检查您运行的两个客户端是在同一NAT设备中还是在不同的NAT设备中。如果您的两个客户端都在同一NAT设备下运行,则可能无法正常工作,因为并非所有NAT设备都支持发夹,即两个客户端都将数据包发送到NAT的外部IP,而该IP需要传递给自身。有关更多信息,请参考以下链接:http
:
//tools.ietf.org/html/rfc4787#section-6
到目前为止还不错,但这里有一个问题:它只适用于特殊情况。 我知道对称NAT(将您的专用IP和端口映射到您想要到达的每个目的地址的特定不同地址的NAT)引起的问题,因此假设我向S1和S2发送一个数据包,S1将看到端口为50263的公共地址,而S2将看到50264)。我还知道,某些非对称NAT要求您先将UDP数据包发送到特定地址,然后才能从同一地址接收数据包。 所以到目前为止我所理解的是,只要您的NA
我正在尝试用打孔实现P2P。流程如下: 两个对等体(P1、P2)将向服务器发送1个数据包。 服务器会对两者进行回复,告诉其他服务器IP:端口 P1和P2接收此UDP数据包,知道对方的外部/公共IP:端口。 P1、P2开始向其他对等方公共IP:端口发送数据包。 一旦对等方接收到其他对等方的数据包,我假设孔已被打孔,并将此套接字提供给我的应用程序。 我在不同的路由器上进行了测试,结果如下: 当P1和P
我知道这个话题并不新鲜。虽然存在各种信息,但健壮的解决方案并没有出现(至少我没有找到)。我有一个用python3编写的P2P守护进程,pie上的最后一个元素是通过TCP连接NAT后面的两个客户端。我得此主题得参考资料: https://bford.info/pub/net/P2pnat/ 如何使两个客户机在连接了一个汇点服务器后直接连接? TCP穿孔问题 到目前为止我所做的: 服务器: 现在,当前
我正在尝试用Boost::ASIO实现NAT打孔。根据我的理解,NAT穿孔器的工作原理是这样的(UDP/TCP): 客户端A绑定到端口并连接到服务器S,客户端B执行相同操作。 当S同时接收到请求和匹配时,它将A的ip和端口发送给B,B发送给A。 a和B接收对方的ip和端口,现在它们从同一端口向对方发送消息并形成连接(因为它们正在等待回复?) 如果没有成功的或,我似乎无法运行任何。当然,当目标端口没
我设置了两台PC,一台是本地网络中的客户端,另一台是公共网络上的服务器。 测试步骤是 -- 1) 端口 33333 上的客户端侦听 udp 2) 端口 22222 上的服务器侦听 UDP 1) 客户端将 udp 发送到服务器 2) 服务器收到数据并发回 当我在我的测试网络上测试代码时,它是正常的。 如果把服务器放在真正的互联网上,服务器可以从客户端获取消息,客户端无法从服务器获得响应。怎么了? 下
大多数人似乎都通过UDP使用NAT穿孔,但在我的例子中,我需要使用TCP(这是事实,在有人问“为什么不使用UDP?”之前)我找不到任何示例代码或至少一个适当的教程。我能找到的都是理论上的附属物,但没有使用套接字或TCPClients(我更喜欢套接字)。 有人能给我链接一些示例代码吗?我可以用这些示例代码连接两个NAT后的客户端,或者用示例代码链接到完整的教程?我知道在.NET中很难实现这个目标(我