首页 文章

使用DatagramSocket的Java UDP STUN打孔

提问于
浏览
2

我试图通过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 回答

  • 2

    你实现的不是真正的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客户端库结合使用 .

相关问题