前言 :
自从家里有小孩后手机里的照片多的没地方放,又想实时能查看,家里人的手机都拍了宝宝照片视频,也没法相互查看,所以这个场景下不管是云备份,qq空间都无法实现这个诉求,腾讯相册的小程序倒是好,但是貌似经常有bug,再说数据放在家里是最安全的。前段时间看头条上面说花生壳的内网穿透,虽然没用过也不想花钱,就想能不能自己搞一个内网穿透,就想查查花生壳实现内网穿透的原理,百度了一批突然发现有个标题为“无需花生壳,阿里云解析实现内网穿透”的文章,好好拜读了一下,觉得自己应该也可以弄,因为我有一个阿里云的虚拟服务器正在使用,设置个二级域名就可以了,这里需要谢谢 “没文化的查哥”看了他的文章才知道该怎么做,他是用Python 实现的,而我了 又不会Python,所以了不管怎么样先试试。
这里了需要先说说实现内网穿透所需要的条件,如果阁下不具备就随便看看吧。
1.你需要有个域名,如果没有也可以买一个,那种一般的域名一年也就十几块,几块的,买个十年也花不了多少钱。
2.既然要做ddns,那你需要一个公网IP,现在多数家里的网都是私网,需要去申请,我家里用的是电信的,我打了个客服10000号申请了一下,第三天就给我搞定了,联通移动的网络是否好申请,我不知道,听说不好申请,因为分给他们的地址少。这里什么是私网什么是公网呢?举个例子 你家里有台路由器 ,家里的电脑电视手机获取到的ip就是路由器分配的ip地址是私网ip,但是路由器拨号上网获得的ip地址是电信公司分配的,那么如果说路由器使用的ip地址是公网。同样道理好比说电信公司就有一台巨大路由器,然后家家户户用的路由器上获得的ip地址就是电信公司这个大路由器分配的。而电信公司的路由器就是使用公网IP,我们的路由器上拨号获取的ip是私网,我们想要使用公网ip就得向人家申请。中国电信握有大量公网ip所以好申请一些,那么为什么不给家家分配公网IP呢?是因为用户太多了 公网IP不够用,再说公网ip比私网IP要好 要更快。扯远了...。
3.不管你内网穿透要干啥,家里总是需要一台服务器,例如闲置多年的烂笔记本,扔了可惜,用又用不着的那种,最好功耗低一点的,不费电。我家里有两台旧笔记本(只能运行winxp系统的),一台windows平板,有一台是个华硕的上网本,功耗低,一台是上学时买的好像09年买的吧。 windows 平板是山寨的那种运行的windows 8 但是没有网线插口,做服务器功耗挺美,但是网络可能不行,就选择华硕上网本安装centOs
4.其他比如说家里没网没路由器 那那就...
说说实现原理
即使是公网ip它也是会改变的,不会一直不变,具体原因就不说了,因此我们需要利用阿里云的云解析API做一个动态改变解析值的这么一个组件,然后在服务器上设置定时执行这个组件,当发现公网ip变了以后立即把解析值给修改成最新的ip,以保证域名解析始终指向你家里的服务器。
一、 实现步骤 :
1.申请一个公网ip
2.阿里云域名(要备案,过程麻烦但是也是比较好备案的),把需要解析的域名解析值设置为这个公网ip
3.设置路由器,路由器的端口映射可以把网络上的请求指向你局域网的服务器,注意路由器要根据mac地址给服务器分配静态ip,不能让服务器自动获取ip 当然 你也可以把你的服务器就放在猫旁边,直接连接猫获取ip,就省去了端口映射。
4.服务器,可以是linux 或者windos,不管是要用web ftp server...
5.把开发好的组件放进服务器
以上步骤简单就这样,我们下面重点说这个组件开发,开发组件用的是Python ,搭建Python服务器的方法就不说了,我Python 也是小白,只花了两天看了看runoob的python3的教程,我主要是做php和前段的,下面代码写的不好的或者注释不正确的希望大牛不要笑话,指正一下。
实现的思路都是来源于阿里云的API文档 https://help.aliyun.com/document_detail/29776.html
二、 实现原理 :
先获取当前公网ip 然后获取阿里云域名列表,找出要修改的域名解析值,然后跟公网ip做对比,如果两个ip不一样说明公网ip变心了 就需要把解析值修改成新来的ip
现在开始直接贴代码:
#1 获取公网ip
import requests #异步请求库 安装方法终端运行: pip install requests
import re
def get_local_ip(self):
#通过向http://txt.go.sohu.com/ip/soip 网站发送get请求,会获取到当前局域网所在外网(公网)ip信息,返回的是一串字符串,注意使用异步请求需要requests库支持
text = requests.get("http://txt.go.sohu.com/ip/soip").text
#通过正在表达式解析出返回的ip地址
ip = re.findall(r'\d+.\d+.\d+.\d+',text)
return ip[0]
#2 获取域名列表及修改解析值
#阿里云云解析库 以下4个库安装方法
#pip install aliyun-python-sdk-core
#pip install aliyun-python-sdk-domain
#pip install aliyun-python-sdk-alidns
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkalidns.request.v20150109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
import json #系统带有 如果没有请下载安装
''' AccessKeyId 阿里云后台获取
AccessKeySecret 阿里云后台获取
RegionId 一般默认为 zh-hangzhou
DomainName 要获取的域名 如 xxx.cn 、xxx.com
RrName 解析主记录 可以通过阿里云后台解析列表查看,例如 www.xxx.com 的 主记录为www home.xxx.com 主记录为 home
PageSize 获取解析列表每页显示的数量,默认20 最多200
'''
client = AcsClient(AccessKeyId, AccessKeySecret, RegionId)
request = DescribeDomainRecordsRequest()
request.set_accept_format('json') #返回的数据格式 为json
request.set_DomainName('你要解析的域名DomainName ') # 要获取的域名
request.set_PageSize('每页显示记录的数量值PageSize ') # 每页显示记录数量
response = client.do_action_with_exception(request)
dns_list = str(response, encoding='utf-8') #获取得到json字符
list_boj = json.loads(dns_list); #将json字符串转为python字典
record = list_boj['DomainRecords']['Record']; #获取dns列表中的需要修改的dns组 格式如{"RR": "xx","Line": "default","Status": "ENABLE","Locked": false,"Type": "A","DomainName": "xxx.cn","Value": "0.0.0.0","RecordId": "123456789...",...} ,{"":"",....}
#需要得到的参数
RecordId = ''
Type = ''
RR = ''
ThisIp = ''
#遍历record 得到RR:主记录 RecordId:记录id Type:记录类型 ThisIp:当前解析的值
for x in record:
rtop = x['RR']; #主记录 用于下面判断是不是与修改设置的RrName 一致,如果一致就把所需要的参数拿出来并跳出循环
if(rtop == RrName ):
RecordId = x['RecordId'];
Type = x['Type'];
RR = x['RR'];
ThisIp = x['Value'];
break;
if(‘公网ip’ != ThisIp):
requests = UpdateDomainRecordRequest()
requests.set_accept_format('json')
requests.set_RecordId(RecordId) #记录id
requests.set_RR(RR) #主记录
requests.set_Type(Type) #记录类型如 A
requests.set_Value('新的公网ip') #修改为当前公网IP
responses = client.do_action_with_exception(requests)
infJson = str(responses, encoding='utf-8')
infObj = json.loads(infJson); # 把返回值解析一下,如果成功返回则返回 此记录值的 RecordId
if(RecordId == infObj['RecordId']):
inf = 'IP修改成功!RecordId:'+infObj['RecordId']
else:
inf = 'IP修改失败'
else:
inf = 'ip相同不用修改!'
return inf;
以上代码为解决思路,使用此代码注意自己的使用逻辑,需要按照自己的逻辑修改一下,注意缩进问题。
部分代码截图如下:
希望能帮助到有需求的人。不正确的请指正。
后续做好了整个流程可以的话再分享
需要源码的可以私信哦
评论留言