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。服务器如何获取不知道。