udp内网穿透 两个内网互联
1,在有外网ip的机器上启动server。

package udp; import java.net.DatagramPacket; import java.net.InetSocketAddress; public class Server extends UDPAgent { public static void main(String[] args) throws Exception { new Server(2008).start(); } public Server(int port) { super(port); } public void onReceive(DatagramPacket rec) { try { println("=== Server OnReceive ==="); String s = rec.getSocketAddress().toString(); String msg = new String(rec.getData(), rec.getOffset(), rec.getLength()); //if receive client's first log on, return its NAT port. if (msg.trim().startsWith("register")) { DatagramPacket outPacket = new DatagramPacket(s.getBytes(), s.length(), rec.getSocketAddress()); // 发送数据 ds.send(outPacket); } } catch (Exception e) { e.printStackTrace(); } } public void doSend(String cmd) throws Exception { println("====server's doSend====="); println("CMD: " + cmd); String[] s = cmd.split(" ", 4); // println("===split cmd========="); // for(String item:s){ // println(item); // } // println("============"); int port = Integer.parseInt(s[2]); InetSocketAddress target = new InetSocketAddress(s[1], port); String msg = s[0]+" "+s[3]; doSend(target, msg.getBytes()); } }
2,在内网启动2个client。

package udp; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Timer; import java.util.TimerTask; public class Client extends UDPAgent { private static final long INTERVAL_TIME = 1 * 20 * 1000; SocketAddress server; // /** * @param args */ public static void main(String[] args) throws Exception { String ip = "211.100.75.221"; int serverPort = 2008; if (args.length > 0) { ip = args[0]; } if (args.length > 1) { serverPort = Integer.parseInt(args[1]); } new Client(ip, serverPort, -1).start(); } public Client(String host, int port, int localPort) { super(localPort); this.server = new InetSocketAddress(host, port); } public void start() throws Exception { println("start"); init(); register(); new Thread(this).start();// recive thread new HeartBeat(); // dead loop receive(); // Cannot reach here. } public void onReceive(DatagramPacket rec) { try { println("=== Client onReceive ==="); //if message not from server, then report to server. // if (!rec.getSocketAddress().equals(server)) { report(rec);//client should return status in order to tell server command execute result. // } String receivedMsg = new String(rec.getData(), rec.getOffset(), rec.getLength()); //if the received message is from server, do server's command. if (rec.getSocketAddress().equals(server)) { doCommand(receivedMsg); }else{ println("Received from other client: "+receivedMsg); } } catch (Exception e) { e.printStackTrace(); } } public void report(DatagramPacket rec) throws Exception { String s = "Report: from " + rec.getSocketAddress() + " messgae:" + new String(rec.getData(), rec.getOffset(), rec.getLength()); byte[] buf = s.getBytes(); println("Report to server"); ds.send(new DatagramPacket(buf, buf.length, server)); } public void register() throws Exception { String msg = "register: " + getLocalAddress() + " " + ds.getLocalPort(); doSend(server, msg.getBytes()); } public String getLocalAddress() throws Exception { InetAddress addr = InetAddress.getLocalHost(); return addr.getHostAddress(); } public void doSend(String cmd) throws Exception { println("====client doSend====="); println("CMD: " + cmd); String[] s = cmd.split(" ", 4); // println("===split cmd========="); // for(String item:s){ // println(item); // } // println("============"); int port = Integer.parseInt(s[2]); InetSocketAddress target = new InetSocketAddress(s[1], port); String msg = s[3]; doSend(target, msg.getBytes()); } class HeartBeat { private Timer timer; public HeartBeat() { println("heartbeat start."); try { this.timer = new Timer(); this.timer.schedule(new ConnSvrTask(), 1000, INTERVAL_TIME); } catch (Exception e) { e.printStackTrace(); } } private class ConnSvrTask extends TimerTask { public ConnSvrTask() { super(); } public void run() { try { byte[] b = "skip".getBytes(); DatagramPacket packet = new DatagramPacket(b, b.length); // 发送心跳 // println("heartbeat"); packet.setSocketAddress(server); ds.send(packet); } catch (Exception e) { e.printStackTrace(); } } } } }
3,他们共同的父类文件

package udp; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.text.SimpleDateFormat; import java.util.Date; import java.util.regex.Pattern; /** * * @author Leo Luo * */ public class UDPAgent implements Runnable { public static void main(String[] args) throws Exception { new UDPAgent(-1).start(); } DatagramSocket ds; byte[] recbuf = new byte[1024]; DatagramPacket rec = new DatagramPacket(recbuf, recbuf.length); static String ipPattern = "([0-9]{1,3}.){3}[0-9]{1,3}"; static String portPattern = "[0-9]{1,5}"; static Pattern sendPattern = Pattern.compile("send " + ipPattern + " " + portPattern + " .*"); int port; public UDPAgent(int port) { this.port = port; } public void init() throws Exception { if (port < 1024 || port > 655535) { ds = new DatagramSocket(); } else { ds = new DatagramSocket(port); } println("====Address info======"); println("InetAddress.getLocalHost: " + InetAddress.getLocalHost()); println("connect getLocalPort:" + ds.getLocalPort()); println("getLocalAddress: " + ds.getLocalAddress().getHostAddress()); println("connect getPort:" + ds.getPort()); println("getInetAddress: " + ds.getInetAddress()); println("getLocalSocketAddress: " + ds.getLocalSocketAddress()); println("getRemoteSocketAddress: " + ds.getRemoteSocketAddress()); println("======================="); } public void start() throws Exception { println("start"); println("LocalPort:" + port); init(); new Thread(this).start();// recive thread receive(); } public void receive() { for (;;) { try { // println("Waiting..."); ds.receive(rec); String msg = new String(rec.getData(), rec.getOffset(), rec.getLength()); if (msg.equals("skip")) continue; //skip heartbeat print out receive. println("=== UDP Agent receive ==="); String line = "Received from " + rec.getSocketAddress() + ": [" + msg + "]"; println(line); onReceive(rec); } catch (Exception e) { e.printStackTrace(); } } } public void onReceive(DatagramPacket rec) { } public void doCommand(String cmd) throws Exception { // command: // 1. send xxx.xxx.xxx.xxx xxx ******************* // if (sendPattern.matcher(cmd).matches()) { if (cmd.startsWith("send")) { doSend(cmd); } } public void doSend(String cmd) throws Exception { println("CMD: " + cmd); String[] s = cmd.split(":", 4); // println("===split cmd========="); // for(String item:s){ // println(item); // } // println("============"); int port = Integer.parseInt(s[2]); InetSocketAddress target = new InetSocketAddress(s[1], port); byte[] bs = "Say Hello!".getBytes(); doSend(target, bs); } public void doSend(SocketAddress addr, byte[] data) throws Exception { println("target:" + addr); DatagramPacket pack = new DatagramPacket(data, data.length, addr); ds.send(pack); } public void run() { BufferedReader reader = new BufferedReader(new InputStreamReader( System.in)); try { String line = reader.readLine(); while (!"exit".equals(line)) { doCommand(line); line = reader.readLine(); } System.exit(0); } catch (Exception e) { e.printStackTrace(); } } SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd H:m:s"); public void println(String s) { System.out.println(format.format(new Date()) + ": " + s); } }
在服务器端输入指令,根据连接上来的两个客户端ip:
send 192.168.11.100 57771 192.168.11.100 57768 message here
即让第一个客户端给第二个发送消息。
如果共同位于同一个nat后,ping不同彼此的ip。需要指定内网ip。服务器如何获取不知道。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2013-08-06 Ubuntu 13.04下构建Qt5开发环境