UDP打洞的具体原理就不细说了文章还是很多,说下我的网络环境,家里台式电脑网线连的家里路由器(移动宽带),公司台式电脑网线连的公司路由器(电信宽带),一台有公网IP的华为云主机(我是试用一个月的)
1、华为云主机UDPServer代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.LinkedHashMap;
public class UDPServer {
private static ArrayList<String> c = new ArrayList<String>();
public static void main(String[] args) throws IOException, InterruptedException {
DatagramSocket server = new DatagramSocket(9999);
byte[] bytes = new byte[1024];
while (true) {
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
server.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
String s = address.getHostAddress()+":"+port;
System.out.println("收到->"+s+"的消息:");
if (!c.contains(s)){
c.add(s);
}
for (String s1 : c) {
if (!s1.equals(s)){
byte[] b = ("this is server:"+s1).getBytes();
DatagramPacket packet1 = new DatagramPacket(b, b.length, address,port);
server.send(packet1);
}
}
}
}
}
2、公司台式电脑的UDPClient端代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
public class UDPClient {
private static final ArrayList<String> c = new ArrayList<String>();
private static boolean b=true;
public static void main(String[] args) throws IOException, InterruptedException {
DatagramSocket socket = new DatagramSocket();
new Thread(()->{
try {
byte[] bytes = new byte[1024];
DatagramPacket packet1 = new DatagramPacket(bytes, bytes.length);
while (true){
socket.receive(packet1);
String receive = new String(bytes,0,packet1.getLength());
if (receive.contains("server")){
c.add(receive);
}
if (receive.contains("client")){
b = false;
}
System.out.println(receive);
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
byte[] data1 = "client:my is company".getBytes();
while (true){
if (b) {
DatagramPacket packet1 = new DatagramPacket(data1, data1.length, InetAddress.getByName("121.36.221.82"),9999);
socket.send(packet1);
}
if (!c.isEmpty()){
DatagramPacket packet2 = new DatagramPacket(data1, data1.length, InetAddress.getByName(c.get(0).split(":")[1]), Integer.parseInt(c.get(0).split(":")[2]));
socket.send(packet2);
}
TimeUnit.SECONDS.sleep(2);
}
}
}
3、家里的台电机和UDPClient的代码一样,修改sleep的时间为1秒,为了区分客户端发送的消息company可以改为family。121.36.21.88是我的华为云主机公网IP,代码也没有什么逻辑就没写注释,先启动Server,再启动两个客户端代码,如果客户端不停打印出my is company的提示说明打洞成功。成功后客户端不会再给Server发送消息,后面再贴Android的demo