2012-03-28 127 views
2

我想通过NAT向客户端发送udp数据包,我们都属于不同的NAT,因此我们熟悉STUN的理论,因此实现此目的的方式是“打孔”通过通过一个简单的STUN服务器我们的方式..Java UDP STUN使用DatagramSocket打孔

基本上服务器直接返回外部IP地址,那就是“连接”,我就可以用它来将数据包发送给其他客户端的端口但是尽管我们设法让对方的外部IP和端口..我们仍然无法收到任何对方发送后...在搜索论坛和头几个小时的抓挠我们仍然无法想出一个解决方案......想知道是否有谁熟悉STUN能够给我们一些点TER值或在哪里,我们已经走了错误的建议......

下面是我们的小客户,我们已经写了...

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(); 
} 

} 

回答

2

你实现什么是不是真正的STUN协议,但很可能足够了。 :)

但我想我在你的代码中看到两个问题。

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

  2. 只是因为你知道远程主机的外部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客户端库结合使用。