参考:http://blog.csdn.net/jacman/article/details/

1: 启动一个Server.

2: 启动两个Client.

然后从Server端的Console里边可以看到两个Client的NAT后的地址和端口。

在Server段输入命令 send:xxx.xxxx.xxx.xxx:xxxx

会给send后面的ip:port发送hello。

因为NAT 路由器一段时间会断开连接,我们就再也找不到内网的客户端了,所以需要心跳保持连接。

1,udp父类

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;
                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);
    }
}

2,服务器端

package udp;

public class Server extends UDPAgent {
    public static void main(String[] args) throws Exception {
        new Server(2008).start();
    }

    public Server(int port) {
        super(port);
    }
}

3,客户端

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("=== On Received ===");
            report(rec);
            if (rec.getSocketAddress().equals(server)) {
                doCommand(new String(rec.getData(), rec.getOffset(),
                        rec.getLength()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void report(DatagramPacket rec) throws Exception {
        String s = " Server: " + rec.getSocketAddress() + " messgae:"
                + new String(rec.getData(), rec.getOffset(), rec.getLength());
        byte[] buf = s.getBytes();
        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();
    }

    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();
                }
            }
        }
    }
}

UDP 内网穿透 心跳的更多相关文章

  1. udp内网穿透 两个内网互联

    1,在有外网ip的机器上启动server. package udp; import java.net.DatagramPacket; import java.net.InetSocketAddress ...

  2. udp 内网穿透 互发消息

    还差实现内网终端,向服务器发送请求,要对方的内网连接自己,实现打洞.在同一网段,或者公网运行,可以相互聊天. 没有实现检测客户端下线功能. 1,服务器代码 package router; import ...

  3. 内网穿透&UDP打洞

    这两天找度度重新回忆了一下关于内网穿透的事情,在百度文库上找到了两三篇写的比较通俗易懂的文章,把内网穿透做个简单总结. 首先文章建议 Cone NAPT 还有希望,要是 Symmetri NAPT 就 ...

  4. 手写内网穿透服务端客户端(NAT穿透)原理及实现

    Hello,I'm Shendi. 这天心血来潮,决定做一个内网穿透的软件. 用过花生壳等软件的就知道内网穿透是个啥,干嘛用的了. 我们如果有服务器(比如tomcat),实际上我们在电脑上开启了服务器 ...

  5. 四、frp内网穿透服务端frps.ini各配置参数详解

    [必须]标识头[common]是不可或缺的部分 [必须]服务器IPbind_addr = 0.0.0.00.0.0.0为服务器全局所有IP可用,假如你的服务器有多个IP则可以这样做,或者填写为指定其中 ...

  6. 使用FRP做内网穿透

    Github地址:https://github.com/fatedier/frp 什么是FRP? frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 h ...

  7. 一款带Web面板的轻量级、高性能内网穿透工具:nps使用教程

    说明:内网穿透工具之前已经介绍了不少了,比如Frp.lanproxy.Holer等,现在再介绍个带Web面板的穿透工具nps,之前叫easyProxy,只是改名了而已,该工具是一款使用go语言编写的轻 ...

  8. frp内网穿透学习

    前言 因为自己在内网,但是目标站在外网,这时候可以通过内网穿透工具,将接收到的请求转发到内网,实现在内网的msf可以控制外网的靶机. 也看了一些Ngrok,花生壳的,发现Ngrok.cc这个看文章说有 ...

  9. 如何使用 frp 实现内网穿透

    这有一个专注Gopher技术成长的开源项目「go home」 背景 作为一名程序员,家里多多少少会有一些落了灰的电脑,如果把闲置的电脑变成服务器,不仅有良好的配置,还能用来做各种测试,那就再好不过了. ...

随机推荐

  1. HTML5和css3的总结

    简单的罗列一个HTML5的新东西,以后的几天里详细的过一遍一个挺有用的网站:www.css88.com [H5的新标签] 用之前的标签完全可以代替的:header footer aside atric ...

  2. javascript替换手机号中间4位

    // 匹配手机号首尾,以类似“123****8901”的形式输出 '12345678901'.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'); 此段正则匹配字符串 ...

  3. center

    center标签对其包围的文本进行水平居中处理

  4. Netty开发UDP协议

    UdpServer package org.zln.netty.five.part07; import io.netty.bootstrap.Bootstrap; import io.netty.ch ...

  5. Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载

    最近 Google 被墙了, 上传一下自己收集的 Android 开发环境, 下面给出的官网链接也可以下载; http://www.androiddevtools.cn/ 1. 百度网盘下载地址 An ...

  6. 爱奇艺招聘uwp开发

    招聘链接:https://job.cnblogs.com/offer/53380/ 工作地点:北京-海淀 工作年限:1年 学历要求:本科 招聘分类:移动开发工程师 工资范围:面议 职位要求 1.扎实的 ...

  7. 好用的SQLSERVER数据库自动备份工具SQLBackupAndFTP(功能全面)

    转载:http://www.cnblogs.com/lyhabc/p/3322437.html 挺好用的SQLSERVER数据库自动备份工具SQLBackupAndFTP(功能全面) 这个工具主要就是 ...

  8. CentOS 7 添加win7启动项——修改默认启动项

    CentOS 7使用grub2引导启动,在win7之后装完CentOS再启动会丢失win7启动项. 首先,添加win7启动项,步骤如下: 1.使用root登陆系统 2.用文本编辑器打开 /boot/g ...

  9. 这些HTML、CSS知识点,面试和平时开发都需要 (转)

    http://www.cnblogs.com/w-wanglei/p/5414979.html No1.HTML 1.网页结构 网页结构一般都包含文档声明DOCTYPE,并且在head中的meta应该 ...

  10. Linux下的MySQL简单操作(服务启动与关闭、启动与关闭、查看版本)

    小弟今天记录一下在Linux系统下面的MySQL的简单使用,如下: 服务启动与关闭 启动与关闭 查看版本 环境 Linux版本:centeros 6.6(下面演示),Ubuntu 12.04(参见文章 ...