静的IPを持つサーバーの助けを借りて、2つのクライアントでUDPホールパンチングを実行したいと思います。サーバーは、ポート7070と7071で2つのクライアントを待機します。その後、サーバーはIPアドレスとポートを相互に送信します。この部分は正常に機能しています。しかし、2つのクライアント間の通信を確立できません。さまざまなWifiネットワークと3Gモバイルネットワークでコードを試しました。クライアントプログラムは、IO例外「ホストへのルートがありません」をスローします。クライアントコードは両方のクライアントに使用されます。ポート7070で1回、7071で1回実行されます。
UDPホールパンチングの概念を正しく実装したと思いますか?それを機能させるためのアイデアはありますか?これが最初にサーバーコードで、次にクライアントコードです。
ご協力ありがとう御座います。
サーバーのコード:
public class UDPHolePunchingServer {
public static void main(String args[]) throws Exception {
// Waiting for Connection of Client1 on Port 7070
// ////////////////////////////////////////////////
// open serverSocket on Port 7070
DatagramSocket serverSocket1 = new DatagramSocket(7070);
System.out.println("Waiting for Client 1 on Port "
+ serverSocket1.getLocalPort());
// receive Data
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket1.receive(receivePacket);
// Get IP-Address and Port of Client1
InetAddress IPAddress1 = receivePacket.getAddress();
int port1 = receivePacket.getPort();
String msgInfoOfClient1 = IPAddress1 + "-" + port1 + "-";
System.out.println("Client1: " + msgInfoOfClient1);
// Waiting for Connection of Client2 on Port 7071
// ////////////////////////////////////////////////
// open serverSocket on Port 7071
DatagramSocket serverSocket2 = new DatagramSocket(7071);
System.out.println("Waiting for Client 2 on Port "
+ serverSocket2.getLocalPort());
// receive Data
receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket2.receive(receivePacket);
// GetIP-Address and Port of Client1
InetAddress IPAddress2 = receivePacket.getAddress();
int port2 = receivePacket.getPort();
String msgInfoOfClient2 = IPAddress2 + "-" + port2 + "-";
System.out.println("Client2:" + msgInfoOfClient2);
// Send the Information to the other Client
// /////////////////////////////////////////////////
// Send Information of Client2 to Client1
serverSocket1.send(new DatagramPacket(msgInfoOfClient2.getBytes(),
msgInfoOfClient2.getBytes().length, IPAddress1, port1));
// Send Infos of Client1 to Client2
serverSocket2.send(new DatagramPacket(msgInfoOfClient1.getBytes(),
msgInfoOfClient1.getBytes().length, IPAddress2, port2));
//close Sockets
serverSocket1.close();
serverSocket2.close();
}
クライアントのコード
public class UDPHolePunchingClient {
public static void main(String[] args) throws Exception {
// prepare Socket
DatagramSocket clientSocket = new DatagramSocket();
// prepare Data
byte[] sendData = "Hello".getBytes();
// send Data to Server with fix IP (X.X.X.X)
// Client1 uses port 7070, Client2 uses port 7071
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, InetAddress.getByName("X.X.X.X"), 7070);
clientSocket.send(sendPacket);
// receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
clientSocket.receive(receivePacket);
// Convert Response to IP and Port
String response = new String(receivePacket.getData());
String[] splitResponse = response.split("-");
InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));
int port = Integer.parseInt(splitResponse[1]);
// output converted Data for check
System.out.println("IP: " + ip + " PORT: " + port);
// close socket and open new socket with SAME localport
int localPort = clientSocket.getLocalPort();
clientSocket.close();
clientSocket = new DatagramSocket(localPort);
// set Timeout for receiving Data
clientSocket.setSoTimeout(1000);
// send 5000 Messages for testing
for (int i = 0; i < 5000; i++) {
// send Message to other client
sendData = ("Datapacket(" + i + ")").getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
clientSocket.send(sendPacket);
// receive Message from other client
try {
receivePacket.setData(new byte[1024]);
clientSocket.receive(receivePacket);
System.out.println("REC: "
+ new String(receivePacket.getData()));
} catch (Exception e) {
System.out.println("SERVER TIMED OUT");
}
}
// close connection
clientSocket.close();
}
[〜#〜] update [〜#〜]コードは正常に機能しています。私は今、2つの異なるホームネットワークでそれを試しましたが、機能しています。しかし、それは私の3Gまたは大学のネットワークでは機能していません。 3Gでは、clientSocketを開閉した後でも、NATが2つのポート(クライアントポートとルーターが割り当てたポート)を再度マッピングしていることを確認しました。理由は誰かわかります。それでは機能していませんか?
UDPホールパンチングは、すべてのタイプのNATで実現できるわけではありません。すべてのタイプのNATに対して定義された普遍的または信頼できる方法はありません。対称NATの場合でも非常に困難です。
NATの動作に応じて、UDPパケットを送信するデバイスごとにポートマッピングが異なる場合があります。たとえば、AがBにUDPパケットを送信すると、50000のようなポートが取得される場合があります。 AはUDPパケットをCに送信し、50002のような異なるマッピングを取得する場合があります。したがって、サーバーにパケットを送信するとクライアントにポートが与えられ、他のクライアントにパケットを送信すると他のポートが与えられる場合があります。
NATの動作について詳しくは、こちらをご覧ください。
http://tools.ietf.org/html/rfc4787
対称NAT(別のモバイルネットワークに接続する3Gネットワーク)の場合、マルチUDPホールパンチングを実行する必要があります。
見る:
https://drive.google.com/file/d/0B1IimJ20gG0SY2NvaE4wRVVMbG8/view?usp=sharing
http://tools.ietf.org/id/draft-takeda-symmetric-nat-traversal-00.txt
https://www.goto.info.waseda.ac.jp/~wei/file/wei-apan-v10.pdf
それか、TURNサーバーを介してすべてのデータを中継します。