
// 本範例不適合用於對稱行網路,要解決此問題請先讓 Client 連線至 Server ,讓 Client 知道自己的 (公開/內部 IP ) 與其他人的 (公開/內部 IP ) ,再檢查自己公開 IP 是否與其他人的公開 IP 重複,如果有重複代表自己處於對稱行網路中,將使用內部 IP 進行通訊即可。
Java 伺服器程式碼:
package javaapplication1;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
public class JavaApplication1 {
public static void main(String[] args) throws Exception {
byte[] buffer = new byte[65507];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
DatagramSocket ds = new DatagramSocket(5555); // Set Server Port
System.out.println("伺服器啟動於 : "
+ InetAddress.getLocalHost().getHostAddress() + ":" + ds.getLocalPort());
String msg = "No Message...";
HashMap map = new HashMap();
while (true) {
dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp);
msg = new String(dp.getData(), 0, dp.getLength());
String ipPort = dp.getAddress().getHostAddress() + ":" + dp.getPort();
// 只要一連線就會把 IP 放進 map 裡
map.put(ipPort, "");
System.out.println(ipPort + " 傳來的訊息 : " + msg);
// 回傳他們自己的 外網IP
dp = new DatagramPacket(ipPort.getBytes(), ipPort.length(), dp.getAddress(), dp.getPort());
ds.send(dp);
// 如果 2 個人上線了...
if (map.size() == 2) {
ArrayList a = new ArrayList();
for (Object ip_Port : map.keySet()) {
a.add(ip_Port.toString());
}
for (Object ip_Port : map.keySet()) {
String temp = "";
for (int i = 0; i < a.size(); i++) {
// 如果現在這個IP不等於之前存放在 map 裡的IP
// 簡單來說就是只要獲取對方的IP,並不需要用到自己的IP
if (!a.get(i).equals(ip_Port)) {
temp += a.get(i);
}
}
// 為每個連線端發送對方的 IP:Port
dp = new DatagramPacket(temp.getBytes(), temp.length(), getIP(ip_Port), getPort(ip_Port));
ds.send(dp);
}
}
}
}
static InetAddress getIP(Object ipPort) throws UnknownHostException {
return InetAddress.getByName(ipPort.toString().split(":")[0]);
}
static int getPort(Object ipPort) {
return Integer.valueOf(ipPort.toString().split(":")[1]);
}
}