Java UDP STUN 使用 DatagramSocket 打洞

标签 java udp nat datagram stun

我正在尝试通过 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();
}

}

最佳答案

您实现的不是真正的 STUN 协议(protocol),但可能就足够了。 :)

但我认为我在您的代码中发现了两个问题。

  1. 您没有保存本地端口号。从 stun 服务器收到响应后,您需要调用 socket.getLocalPort 来找出与“映射端口”对应的内部端口号。映射的端口是您的 stun 服务器看到您的端口。您的 NAT 将继续将来自 PC IP 的出站流量映射到该映射端口,但前提是您使用相同的本地端口。因此,在与对等点的后续连接中,在同一端口上创建数据报套接字(在关闭原始套接字之后),或者仅重用相同的套接字以进行与对等点的后续通信,因为该套接字已绑定(bind)。

  2. 仅仅因为您知道远程主机的外部 IP 地址及其本地套接字的端口映射,并不意味着他的 NAT 将转发您的数据包。大多数 NAT 都以“IP 和端口受限”的方式运行。这意味着,如果它知道同一远程主机的 IP 和端口有相应的出站 UDP 数据包,则仅允许入站流量(包括 UDP 数据包)通过 NAT。如果没有此规则,它将不知道将数据包转发到 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 打洞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9906706/

相关文章:

java - RxJava - Observable - 多个过滤器调用与一个过滤器调用

java - SNMP 响应为空 [SNMP4j]

linux - 获取 Linux 上特定主机之间的 UDP 流量统计

java - 两个 android 设备之间的 TCP 连接(即使使用 NAT)

java - Java中的字符串位置解析

java - 使用 java 运行 jython 字节码

.net - .Net WCF NAT 穿越的最佳实践

java - 如何使 RMI 服务器同时为本地客户端(同一网络内)和外部客户端工作

udp - 订购 react 性扩展事件

c - 另一个进程是否接收到对 UDP 数据报的响应?