[点晴永久免费OA]C#利用阿里云云解析API实现动态域名解析(ddns)【含可执行文件和源码】
当前位置:点晴教程→点晴OA办公管理信息系统
→『 经验分享&问题答疑 』
前言:懒人可以直接往下看,有代码和全部资源可以下载。此文章是先前文章的定时版,主要是添加了定时执行的功能,并且将代码中的配置项放置到了app.config文件中,方便不懂开发的朋友修改使用。 遇到的问题:公司的网络没有固定的公网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,尽量右键以管理员身份运行,同时注意别被安全软件拦截了。 该文章在 2019/9/5 23:05:53 编辑过
|
关键字查询
相关文章
正在查询... |