Java UDP STUN Перфорация отверстий с помощью DatagramSocket - PullRequest
2 голосов
/ 28 марта 2012

Я пытаюсь отправить пакет udp клиенту через NAT, мы оба принадлежим к другому 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 голосов
/ 08 июня 2012

То, что вы реализовали, не является истинным протоколом STUN, но, вероятно, будет достаточным.:)

Но я думаю, что я вижу две проблемы в вашем коде.

  1. Вы не сохраняете номер локального порта.После того, как вы получите ответ от stun-сервера, вам нужно вызвать socket.getLocalPort, чтобы узнать, какой номер вашего внутреннего порта соответствует «сопоставленному порту».Сопоставленный порт - это порт, который видит ваш сервер оглушения.NAT будет продолжать отображать исходящий трафик с IP-адреса вашего компьютера на этот сопоставленный порт, но только если вы используете тот же локальный порт.Поэтому при последующем соединении с вашим партнером создайте сокет дейтаграммы на том же порту (после закрытия исходного сокета) или просто используйте этот же сокет для последующего обмена данными с партнером, поскольку сокет уже связан.

  2. То, что вы знаете внешний IP-адрес удаленного хоста и его сопоставление портов для локального сокета, не означает, что его NAT будет пересылать ваши пакеты.Большинство NAT работают как «IP и порт ограничен».Это означает, что он будет разрешать входящий трафик, включая UDP-пакеты, только через NAT, если он знает, что существует соответствующий исходящий UDP-пакет для того же IP-адреса и порта удаленного хоста.Если бы у него не было этого правила, он не знал бы, на какой ПК за NAT отправлять пакет.Типичный метод обхода NAT заключается в том, что оба партнера одновременно отправляют простые однобайтовые дейтаграммы друг другу и повторяют попытки (более одного раза).Первый пакет пытается покинуть хост и покинуть его собственный NAT, но, вероятно, будет заблокирован удаленным NAT (потому что он не знает, кто вы).Но это заставляет ваш NAT создать запись сопоставления и пересылки для другой стороны, чтобы успешно отправить вам.В конечном итоге оба NAT разрешат и перенаправят трафик между обоими узлами.

Существуют также типы NAT с непредсказуемым поведением портов.(Сопоставление портов изменяется для каждого IP-адреса).Это трудно пройти (с помощью STUN), но обычно работает нормально, если у другой стороны есть хорошо ведущий себя NAT.К счастью, эти типы NAT встречаются реже, чем раньше.

Вот некоторые ссылки:

ICE (стандартный механизм P2P с использованием STUN и TURN): http://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment

Мое P2P-соединение в двух словах Я дал некоторое время назад.

Кроме того, явный штекер для использования моей базы кода сервера STUN .Вы можете использовать его вместе с клиентской библиотекой JStun .

...