【终极版】利用阿里云云解析API实现动态域名解析(ddns),搭建私有服务器【含可执行文件和源码】
前言:懒人可以直接往下看,有代码和全部资源可以下载。此文章是先前文章的定时版,主要是添加了定时执行的功能,并且将代码中的配置项放置到了app.config文件中,方便不懂开发的朋友修改使用。未经许可请勿转载,如有疑问,请联系作者:yxxrui@163.com
我遇到的问题:公司的网络没有固定的公网IP地址,但是需要能够保证的是,每次动态分配的IP地址均为独立的公网IP,只是每次分配后会在1-2天后更换,或者重启路由器后更换,为了能够把这个公网IP利用起来,大家常用的是使用花生壳之类的软件来操作,我使用过花生壳的多款产品,挺好的,就是有一下几个缺点:
1、需要使用花生壳上购买的域名才行,或者使用免费的壳域名,其丑无比
2、不稳定,也很慢
3、限制流量,超流量需要收费
4、限制端口,特定端口需要收费
5、需要在电脑上运行一个花生壳的软件
解决方案:但是为了解决问题,我开始摸索自己搞定它,公司域名从阿里云上购买,阿里云提供云解析技术免费版,提供通过api来管理域名的功能,当我看到该文档的时候直接就看到了希望,解决起来绝对没问题了。首先需要确认一下,有两种情况:
1、公司服务器直接接入网线,这个时候服务器的IP就是公网IP
2、公司服务器链接公司路由器,路由器链接网线,这个时候路由器上是公网IP,而服务器上是局域网IP
第一种情况最简单了,不需要设置什么了,第二种情况需要到路由器设置界面设置端口转发或者直接将全部端口映射到内网的服务器IP上,这样的话,访问公网IP的某个端口时相当于访问内网IP的映射端口,比如路由器IP为125.120.83.30,内网IP为192.168.168.168。可以将路由器中80端口映射到192.168.168.168的80端口上。
到阿里云控制台申请accessKeyId和accessKeySecret,用来调用API的,为了简单起见,先给域名添加一条解析记录,这样就不需要在程序里判断该域名是否已创建,然后可以直接修改解析记录了。比如我的域名为yxxrui.cn,记录值为blog,也就是要把子域名blog.yxxrui.cn指向我自己电脑125.120.83.30上。
下边直接贴出代码:
创建window service用于定时执行解析任务,在Service的OnStart方法中添加:
MainProgram.MyTimerTask();
其中MainProgram.cs为:
1 using System;
2 using System.Configuration;
3 using System.Net;
4 using System.Text;
5 using System.Text.RegularExpressions;
6 using System.Threading;
7 using Aliyun.Acs.Alidns.Model.V20150109;
8 using Aliyun.Acs.Core;
9 using Aliyun.Acs.Core.Profile;
10
11 namespace AliyunDynamicDomain
12 {
13 /// <summary>
14 /// 修改时间:2018-11-18
15 /// 为了方便,特意改写为window service,按时刷新任务
16 /// 不再需要手动设置window自带的定时任务
17 /// 作者:杨浩瑞 yxxrui@163.com
18 /// </summary>
19 class MainProgram
20 {
21 #region 获取基本参数和类属性
22 private static readonly string RegionId = GetConfig("regionId");
23 private static readonly string AccessKeyId = GetConfig("accessKeyId");
24 private static readonly string AccessKeySecret = GetConfig("accessKeySecret");
25 private static string _recordId = GetConfig("recordId");
26 private static readonly string Domain = GetConfig("domain");
27 private static readonly string Rr = GetConfig("rr");
28 private static readonly string IpServer = GetConfig("IpServer");
29 private static int _ttl = 600;
30 private static int _waitTime = 60;
31 private static readonly IClientProfile ClientProfile = DefaultProfile.GetProfile(RegionId, AccessKeyId,
32 AccessKeySecret);
33 private static readonly IAcsClient Client = new DefaultAcsClient(ClientProfile);
34
35 private static readonly object TimerLocker = new object();
36 private static Timer _myTimer;
37 #endregion
38
39 #region 定时任务
40 public static void MyTimerTask()
41 {
42 if (!int.TryParse(GetConfig("TTL"), out _ttl))
43 {
44 _ttl = 600;
45 }
46 if (!int.TryParse(GetConfig("WaitTime"), out _waitTime))
47 {
48 _waitTime = 60;
49 }
50 if (_myTimer != null)
51 {
52 return;
53 }
54 lock (TimerLocker)
55 {
56 if (_myTimer == null)
57 {
58 //第一次开始的时间,1秒后开始执行
59 var startTime = DateTime.Now.AddSeconds(1);
60 var delayTime = (startTime - DateTime.Now);
61 var intervalTime = new TimeSpan(0, 0, 0, _waitTime); //10秒执行一次
62 TimerCallback timerDelegate = DealFun;
63 _myTimer = new Timer(timerDelegate, null, delayTime, intervalTime);
64 }
65 }
66 }
67 #endregion
68
69 #region 执行程序,解析域名
70
71 public static void DealFun(object obj)
72 {
73 try
74 {
75 if (string.IsNullOrWhiteSpace(_recordId))
76 {
77 //如果没有获取过,那么获取一下,然后保存起来
78 _recordId = GetRecordId(Domain, Rr);
79 SaveConfig("recordId", _recordId);
80 }
81 if (string.IsNullOrWhiteSpace(_recordId))
82 {
83 LogHelper.Error("recordId获取失败");
84 return;
85 }
86 //获取成功,并且有变化时
87 string lastIp = GetConfig("lastIP");
88 string curIp = GetIp();
89 if (!curIp.Equals("") && !lastIp.Equals(curIp))
90 {
91 var request = new UpdateDomainRecordRequest
92 {
93 RecordId = _recordId,
94 RR = Rr,
95 Type = "A",
96 Value = curIp,
97 TTL = _ttl,
98 Priority = 10
99 };
100 Client.DoAction(request);
101 SaveConfig("lastIP", curIp);
102 LogHelper.Info("刷新成功");
103 return;
104 }
105 LogHelper.Info("与上次IP一致,无需刷新:" + curIp);
106 }
107 catch (Exception e)
108 {
109 LogHelper.Error(e.ToString());
110 }
111 }
112
113 #endregion
114
115 #region 保存配置信息
116 /// <summary>
117 /// 保存配置信息
118 /// </summary>
119 /// <param name="name"></param>
120 /// <param name="value"></param>
121 private static void SaveConfig(string name,string value)
122 {
123 var cfa = ReadAppConfig();
124 cfa.AppSettings.Settings[name].Value = value;
125 cfa.Save();
126 }
127 #endregion
128
129 #region 获取配置项
130 /// <summary>
131 /// 获取配置项
132 /// </summary>
133 /// <param name="name"></param>
134 /// <returns></returns>
135 private static string GetConfig(string name)
136 {
137 try
138 {
139 var cfa = ReadAppConfig();
140 return cfa.AppSettings.Settings[name].Value;
141 }
142 catch
143 {
144 return "";
145 }
146 }
147 #endregion
148
149 #region 调用阿里云接口获取域名的唯一记录ID
150 /// <summary>
151 /// 调用阿里云接口获取域名的唯一记录ID
152 /// </summary>
153 /// <param name="domain">域名</param>
154 /// <param name="rr">子域名</param>
155 /// <returns></returns>
156 private static string GetRecordId(string domain,string rr)
157 {
158 DescribeDomainRecordsRequest reqq = new DescribeDomainRecordsRequest
159 {
160 DomainName = domain,
161 RRKeyWord = rr
162 };
163 var rss = Client.GetAcsResponse(reqq);
164 foreach (var record in rss.DomainRecords)
165 {
166 if (record.DomainName.Equals(domain) && record.RR.Equals(rr))
167 {
168 return record.RecordId;
169 }
170 }
171 return "";
172 }
173 #endregion
174
175 #region 获取公网IP
176 /// <summary>
177 /// 获取当前电脑的真实外网IP地址,可以自行修改成稳定的
178 /// </summary>
179 /// <returns></returns>
180 private static string GetIp()
181 {
182 var myWebClient = new WebClient { Credentials = CredentialCache.DefaultCredentials };
183 //获取或设置用于向Internet资源的请求进行身份验证的网络凭据
184 var pageData = myWebClient.DownloadData(IpServer);//从指定网站下载数据
185 var all = Encoding.Default.GetString(pageData); //如果获取网站页面采用的是GB2312,则使用这句
186 var regex = @"((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))";
187 var m = Regex.Match(all, regex);
188 if (m.Success)
189 {
190 return m.Value;
191 }
192 return "";
193 }
194 #endregion
195
196 #region 获取配置文件
197 private static Configuration _config;
198 private static Configuration ReadAppConfig()
199 {
200 if (_config == null)
201 {
202 string configPath = AppDomain.CurrentDomain.BaseDirectory+@"/app.config";
203 _config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap()
204 {
205 ExeConfigFilename = configPath
206 }, ConfigurationUserLevel.None);
207 }
208 //MessageBox.Show(config.AppSettings.Settings["serverIp"].Value);
209 return _config;
210 }
211 #endregion
212 }
213 }
为了方便修改参数,特意将所有用到的参数放到了app.config中,该文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<appSettings>
<!--作者:杨浩瑞,yxxrui@163.com,博客:http://www.yxxrui.cn -->
<!-- ############################################## -->
<!--regionId 区域-->
<!--accessKeyId 阿里云accessKeyId-->
<!--accessKeySecret 阿里云accessKeySecret-->
<!--recordId 记录ID,需注意,如果您修改了其他配置,不确定recordId是什么,那么一定要置为空值,系统会自动获取的-->
<!--domain 您的域名,比如:yxxrui.cn-->
<!--rr 您的子域名,比如:blog-->
<!--TTL 域名的TTL值(生存时间),默认600,请按照阿里云说明填写,若不懂,请不要修改-->
<!--lastIP 您的服务器上次的IP地址,用来缓存,您无需修改-->
<!--IpServer 获取IP的服务器地址,如果自己搭建了获取公网IP的服务器,可以换成自己的地址-->
<!--WaitTime 重复执行解析域名的间隔时间,以秒为单位,默认60秒-->
<add key="regionId" value="cn-hangzhou"/>
<add key="accessKeyId" value="123456789"/>
<add key="accessKeySecret" value="123456789987654321"/>
<add key="recordId" value=""/>
<add key="domain" value="yxxrui.cn"/>
<add key="rr" value="in"/>
<add key="TTL" value="10"/>
<add key="lastIP" value=""/>
<add key="IpServer" value="http://2018.ip138.com/ic.asp"/>
<add key="WaitTime" value="5"/>
</appSettings>
</configuration>
之前的版本中,没有做定时任务,只做了以下的工作,但是近期发现使用者还是蛮多的,所以本次终极版专门做了定时任务功能。
1、安装window service,然后会自定启动定时任务
2、获取当前电脑真实公网IP
3、查看当前IP是否有变化
4、若无变化直接退出,若有变化则修改域名解析设置
5、等待WaitTime秒后,跳回步骤 2 继续执行。
此处讲一下如何安装window service,我在安装包装放了一个install.bat,尽量右键 以管理员身份运行,同时主要别被安全软件拦截了。
欢迎关注和赞赏哦!
原文和文件地址:https://www.yxxrui.cn/article/232.shtml
【终极版】利用阿里云云解析API实现动态域名解析(ddns),搭建私有服务器【含可执行文件和源码】的更多相关文章
- 【升级版】如何使用阿里云云解析API实现动态域名解析,搭建私有服务器【含可执行文件和源码】
原文地址:http://www.yxxrui.cn/article/179.shtml 未经许可请勿转载,如有疑问,请联系作者:yxxrui@163.com 我遇到的问题:公司的网络没有固定的公网IP ...
- 如何使用阿里云云解析API实现动态域名解析,搭建私有服务器
原文地址:http://www.yxxrui.cn/article/116.shtml 未经许可请勿转载,如有疑问,请联系作者:yxxrui@163.com 公司的网络没有固定的公网IP地址,但是能够 ...
- 私有云方案——利用阿里云云解析实现DDNS
各位都是程序员,工作中是不是遇到个类似情况.在家里研究的一些开源代码或写的一些demo或试验代码,在工作中正好需要参考一下,但是在家里的电脑上. 虽然这些都可以用云 ...
- 采用阿里的API进行动态域名解析
#!/usr/bin/env python # -*- coding:utf-8 -*- import os from aliyunsdkcore import client from aliyuns ...
- Spring源码解析02:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析
一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...
- 在阿里云主机上基于CentOS用vsftpd搭建FTP服务器
最近需要在一台阿里云的云服务器上搭建FTP服务器,在这篇博文中分享一下我们根据实际需求进行的一些配置. ftp软件用的是vsftpd. vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序 ...
- python 调用阿里云云解析api添加记录
首先安装阿里云SDK pip install aliyun-python-sdk-core pip install aliyun-python-sdk-alidns 可以配合jenkins传递参数 # ...
- 利用可道云kodexplorer在树莓派raspbian上搭建私有云网盘
可道云kodexplorer是一款开源私有云系统,类似于owncloud,Dropbox.SkyDrive,seafile等.将可道云kodexplorer搭建在树莓派上,从而在树莓派上存储.管理家庭 ...
- nodejs版 阿里云开放api签名算法
阿里云 API 签名 github:https://github.com/liuyinglong/aliyun; npm :https://www.npmjs.com/package/aliyun-a ...
随机推荐
- Java基础教程——模拟浏览器发送请求
JAVA访问网页 分别测试使用get和post方法访问网页,可以收到服务器的请求,并写入到html文件中. import java.io.*; import java.net.*; import ja ...
- Java基础教程——Date类和Calendar类
Date类和Calendar类都是关于日期的类,都在java.util包中,使用时需要import. Date java.util.Date类的对象用来表示时间和日期,用得最多的是获取系统当前日期和时 ...
- if判断 和while、for循环
if判断 语法一: if 条件: 条件成立时执行子代码块 代码1 代码2 实例一: sex='female' age=18 is_beautifui=True if sex=='female' ...
- moviepy音视频开发:音频拼接函数concatenate_audioclips介绍
☞ ░ 前往老猿Python博文目录 ░ concatenate_audioclips函数用于将多个音频剪辑进行拼接合成一个顺序播放的剪辑. 调用语法: concatenate_audioclips( ...
- 第6.4节 Python动态表达式计算:eval函数详述
在Python动态执行的函数中,eval是用于执行表达式计算的函数,这个函数用于执行字符串中包含的一个表达式或其编译后对应的代码,不能适用于执行Python语句和完整的代码. 一. 语法 1. ...
- 第8.1节 Python类的构造方法__init__深入剖析:语法释义
一. 引言 凡是面向对象设计的语言,在类实例化时都有构造方法,很多语言的构造方法名与类名一致,Python中类的构造方法比较特殊,必须是__init__特殊方法. 二. 语法释义 1. ...
- PyQt(Python+Qt)学习随笔:视图中类QAbstractItemView的dragDropOverwriteMode属性
老猿Python博文目录 老猿Python博客地址 一.属性的作用 dragDropOverwriteMode属性用于控制视图的拖放行为,如果其值为True,则视图中选定的数据将在拖拽数据放下时被覆盖 ...
- PyQt(Python+Qt)学习随笔:设定toolButton弹出菜单的方法
在Qt Designer中toolButton可以通过popupMode设定菜单弹出的模式,但并不能在Qt Designer中指定toolButton的弹出菜单,toolButton只能通过代码来指定 ...
- Java程序员需要了解的底层知识(一)
硬件基础知识 - Java相关硬件 汇编语言的执行过程(时钟发生器 寄存器 程序计数器) 计算机启动过程 进程线程纤程的基本概念面试高频 - 纤程的实现 内存管理 进程管理与线程管理(进程与线程 ...
- 5、Spring Cloud Ribbon
1.Ribbon简介 (1).Ribbon介绍 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具. Ribbon是Netflix发布的开源项目,主 ...