前面你的文章我已经写了 写了 DMZ 内网映射的 方式。 这样内网主机已经暴露在外网中了。 但是 拨号上网我们的ip是 会变化的。大概规律就是 每次拨号都会变化。如果不拨号,每 24 小时 ip也会自动变化一次。

怎么解决呢? 那就是使用域名。 我们通过域名 来访问 这台机子。并且在 ip 变化的时候 ,让 让域名对应的ip 也跟着变化。 这个过程叫做 DDNS 。就是动态域名解析。

 

DDNS 很多地方都有提供 。阿里有。腾讯云也有。我目前有的域名是腾讯的。所以就用腾讯 实现好了。首先找到腾讯 yun api。

通过 DDNS 解决宽带拨号 ip 变化问题_html

 

这个接口就是给我们 修改 域名和ip对应关系的。 所有我们只需要获取到本地的外网ip然后调用这个接口 就可以了。 

 

我的实现方式 是通过 java 程序 。每隔一段时间取获取本地ip,和上一次的ip做比较,如果不一样,就 调用腾讯云的接口。并且把这个程序加入到开机启动。

 

代码实现:

package com.sbl.pay.subaccount;

public class DDNSParam {
    
    
    public String Action = "RecordModify";
    public Long Nonce = (long) (Math.random()*10000);
    //public String Region = "ap-chengdu";
    public Long Timestamp = System.currentTimeMillis()/1000;
    public String SecretId = "填你自己的id";
    public String SignatureMethod = "HmacSHA1";
    public String Signature = "";
    
    
    
    
    
    
    public String domain = "zhangyukun.club";
    public int recordId  = 380731049;
    public String subDomain = "home";
    public String recordType = "A";
    public String recordLine = "默认";
    public String value = "112.193.146.167";
    
    
    
    
    public String getDomain() {
        return domain;
    }
    public void setDomain(String domain) {
        this.domain = domain;
    }
    public String getRecordLine() {
        return recordLine;
    }
    public void setRecordLine(String recordLine) {
        this.recordLine = recordLine;
    }
    public String getRecordType() {
        return recordType;
    }
    public void setRecordType(String recordType) {
        this.recordType = recordType;
    }
    public String getSubDomain() {
        return subDomain;
    }
    public void setSubDomain(String subDomain) {
        this.subDomain = subDomain;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public String getAction() {
        return Action;
    }
    public void setAction(String action) {
        Action = action;
    }
    public Long getNonce() {
        return Nonce;
    }
    public void setNonce(Long nonce) {
        Nonce = nonce;
    }
    public Long getTimestamp() {
        return Timestamp;
    }
    public int getRecordId() {
        return recordId;
    }
    public void setRecordId(int recordId) {
        this.recordId = recordId;
    }
    public void setTimestamp(Long timestamp) {
        Timestamp = timestamp;
    }
    public String getSecretId() {
        return SecretId;
    }
    public void setSecretId(String secretId) {
        SecretId = secretId;
    }
    public String getSignatureMethod() {
        return SignatureMethod;
    }
    public void setSignatureMethod(String signatureMethod) {
        SignatureMethod = signatureMethod;
    }
    public String getSignature() {
        return Signature;
    }
    public void setSignature(String signature) {
        Signature = signature;

    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.

 

package com.sbl.pay.subaccount;

import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.sbl.pay.subaccount.util.BeanUtils;
import com.sbl.pay.subaccount.util.Core;
import com.sbl.pay.subaccount.util.HttpUtils;

public class Main {

	public static void main(String[] args) {
		
		String url = "https://cns.api.qcloud.com/v2/index.php";

		Map<String, String> params = new HashMap<String, String>();

		DDNSParam param = new DDNSParam();
		
		String urlStr = Core.createLinkString(   BeanUtils.objectToMap( param ) );
		urlStr = "GETcns.api.qcloud.com/v2/index.php?" + urlStr;
		
		String signature = hmacSha1(urlStr, "你的密钥" );
		param.setSignature( signature  );
		params = BeanUtils.objectToStringMap(param);

		String s = HttpUtils.get(url, params);
		System.out.println(s);
		
	}

	public static String hmacSha1(String src, String key) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("utf-8"), "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(src.getBytes("utf-8"));
            return Base64.getEncoder().encodeToString( rawHmac );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.

  

结果 : {"code":0,"message":"","codeDesc":"Success","data":[]}

 

 

下面就是 获取公网ip:  中秋 有空 ,所以搞了一下获取公网IP。百度搜索IP。页面会显示你的公网IP 。所以把这个拔下来就可以了。 如果 你觉得百度 公网Ip 不正确 。那么你可以拔你们家路由器管理界面的。

package com.sbl.pay.subaccount;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;

import org.apache.commons.io.IOUtils;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

public class IPGet {

	public static void main(String[] args) throws Exception {
		System.out.println( getPublicNetworkIP() );
	}

	/**
	 * 得到公网IP
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws ParserException
	 */
	public static String getPublicNetworkIP() throws FileNotFoundException, IOException, ParserException {
		Parser parser = new Parser( new URL("https://www.baidu.com/s?ie=UTF-8&wd=ip").openConnection() );

		String a = IOUtils.toString(new FileInputStream(new File("C:\\Users\\ZHANGYUKUN\\Desktop\\aaa.html")));

		parser.setInputHTML(a);

		AndFilter filter = new AndFilter(new TagNameFilter("span"), new HasAttributeFilter("class", "c-gap-right"));

		NodeList nodeList = parser.parse(filter);

		String ipStr = nodeList.elementAt(0).getChildren().elementAt(0).getText() ;
		ipStr = ipStr.replaceAll("本机IP: ", "");
		return ipStr;
	}

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.

  

结果如下:

通过 DDNS 解决宽带拨号 ip 变化问题_java_02

获取公网IP和 修改IP的接口都搞定了。那么后面就是 吧 这个程序结合起来做成开机启动就可以了

 参考一篇别人的文章。吧jar 做成启动服务。

 

 

 

上面的都是 实现原理。现在说一个简单的方式。检查一下你的路由器里面有没有关于ddns 的设置。

我用的小米路由器。正好有这个设置。

通过 DDNS 解决宽带拨号 ip 变化问题_IP_03

 

 

通过 DDNS 解决宽带拨号 ip 变化问题_java_04

 

 

通过 DDNS 解决宽带拨号 ip 变化问题_IP_05

 

 

 

 

说明一下 。如果使用花生壳的话,那么这里只能使用花生壳的 壳域名。亲测我的腾讯域名不能用。估计只能域名提供商才能向 dns 服务商修改域名和ip的对应关系吧。