Java UDP STUN 打孔与 DatagramSocket
Posted
技术标签:
【中文标题】Java UDP STUN 打孔与 DatagramSocket【英文标题】:Java UDP STUN Hole Punching with DatagramSocket 【发布时间】:2012-04-11 23:56:48 【问题描述】:我正在尝试通过 NAT 向客户端发送 udp 数据包,我们都属于不同的 NAT,我们熟悉 STUN 的理论,因此实现此目的的方法是“打孔”我们的通过一个简单的 STUN 服务器..
基本上,服务器只返回“已连接”的另一个客户端的外部 IP 地址和端口,然后我可以使用它通过 NAT 将数据包发送到客户端......但是尽管我们设法获取了彼此的外部 ip和端口..发送后我们仍然无法收到来自对方的任何东西...在搜索论坛和数小时的头颅后,我们仍然无法提出解决方案...想知道是否有人熟悉STUN 能够给我们一些关于我们哪里出错的指示或建议......
下面是我们写的小客户端...
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import javax.swing.JOptionPane;
public class Client
DatagramSocket socket;
public Client()
try
socket = new DatagramSocket();
String data = "Initiate Stun Server";
byte[] receive = data.getBytes();
InetAddress host = InetAddress.getByName("the.stun.server.ipaddress");
DatagramPacket pk = new DatagramPacket(receive,receive.length,host,9345);
socket.send(pk); //send packet to server to initiate udp communication
//spawn a new Thread to listen for any incoming packets
new Thread()
public void run()
byte[] r;
DatagramPacket rp;
while(true)
System.out.println("Start listening on new socket");
r = new byte[1024];
rp = new DatagramPacket(r,r.length);
try
socket.receive(rp);
System.out.println(new String(rp.getData()));
catch (IOException e)
e.printStackTrace();
.start();
String m = JOptionPane.showInputDialog(null,"Enter message to send");
InetAddress connect = InetAddress.getByName(JOptionPane.showInputDialog(null,"Enter address to send message to"));//This is where we input the external ip
int connectPort = Integer.parseInt(JOptionPane.showInputDialog(null,"Enter port of the addressee"));//input port
DatagramPacket p = new DatagramPacket(m.getBytes(),m.getBytes().length,connect,connectPort);
socket.send(p);
catch (SocketException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (UnknownHostException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
public static void main(String args[])
Client c = new Client();
【问题讨论】:
【参考方案1】:您实现的不是真正的 STUN 协议,但可能就足够了。 :)
但我认为我在您的代码中发现了两个问题。
您没有保存本地端口号。从 stun 服务器返回响应后,您需要调用 socket.getLocalPort 以找出与“映射端口”相对应的内部端口号。映射端口是您的 stun 服务器看到您的端口。您的 NAT 将继续将来自您 PC 的 IP 的出站流量映射到该映射端口,但前提是您使用相同的本地端口。因此,在您与对等方的后续连接中,在同一端口上创建数据报套接字(在关闭原始套接字之后),或者只是重用同一个套接字来与对等方进行后续通信,因为套接字已经绑定。
仅仅因为你知道远程主机的外部 IP 地址和他的本地套接字的端口映射,并不意味着他的 NAT 会转发你的数据包。大多数 NAT 以“IP 和端口受限”的方式运行。这意味着,如果它知道同一远程主机的 IP 和端口有相应的出站 UDP 数据包,它将只允许通过 NAT 的入站流量,包括 UDP 数据包。如果它没有这个规则,它就不会知道将数据包转发到 NAT 后面的哪台 PC。典型的 NAT 穿越技术是让双方同时向对方发送简单的 1 字节数据报,并反复尝试(不止一次)。第一个数据包试图离开主机并离开它自己的 NAT,但很可能会被远程 NAT 阻止(因为它不知道你是谁)。但它确实会导致您的 NAT 创建一个映射和转发条目,以便对方成功发送给您。最终,两个 NAT 都将允许并转发两个对等方之间的流量。
还有一些类型的 NAT 具有不可预测的端口映射行为。 (端口映射按 IP 更改)。这些很难遍历(使用 STUN),但如果对方有一个表现良好的 NAT,通常可以正常工作。幸运的是,这些类型的 NAT 比以前少了。
这里有一些链接:
ICE(通过使用 STUN 和 TURN 实现的 P2P 标准机制):http://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment
我的P2P connectivity in a nutshell answer 我给了一段时间。
另外,一个公然使用my STUN server code base 的插件。您可以将它与JStun 客户端库结合使用。
【讨论】:
以上是关于Java UDP STUN 打孔与 DatagramSocket的主要内容,如果未能解决你的问题,请参考以下文章