【终极版】利用阿里云云解析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端口上。

到阿里云控制台申请accessKeyIdaccessKeySecret,用来调用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

转载于:https://www.cnblogs.com/yxxrui/p/AliyunDynamicDomain.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值