如果將PC電腦變成web服務器:使用python3監(jiān)測公網(wǎng)IP實現(xiàn)DDNS

如果將PC電腦變成web服務器:使用python3監(jiān)測公網(wǎng)IP實現(xiàn)DDNS
上一篇文章中,我們使用Nignx的反向代理和端口轉發(fā)實現(xiàn)域名訪問家里主機上的web了。
由于家庭寬帶基本都是動態(tài)IP,每當你重啟一次光貓,IP地址就會變化一次。當光貓因為停電、故障、維護等原因重啟過后,網(wǎng)站就無法訪問了。網(wǎng)上基本的解決方法是使用花生殼做DDNS(動態(tài)域名解析),但那個需要綁定自己的域名要付費不說,且linux無法使用,本文通過python和socket實現(xiàn)DDNS。
(因平臺原因本文中www即為xxx ,com即為zzz,http/ccccc即為cccc/ccccc)
?
這個程序是一個典型的C/S程序,有客戶端和服務端。畫張草圖來解釋下這個python程序的運行原理:
?

說明:這個程序分為客戶端和服務端??蛻舳诉\行在內(nèi)網(wǎng)主機上,服務端運行在服務器上??蛻舳藭扛?0秒主動檢測一次自己的公網(wǎng)IP是否變化,如果地址改變,則會通過socket連接服務端程序,把改變后的地址發(fā)送給服務端。服務端接收到地址后,先校驗一遍地址是否合fa,如果地址OK,那么將地址寫入Nginx的反代理配置文件,反代理生效并指向新的內(nèi)網(wǎng)主機公網(wǎng)地址,從而實現(xiàn)DDNS。
一、程序的使用環(huán)境
服務器系統(tǒng)需是centos7,內(nèi)網(wǎng)主機可以是windows或者centos7。
注意:程序是使用python3開發(fā)的,不兼容python2。因此如果使用centos7默認自帶的python2運行會報錯。
1. 服務端環(huán)境:python3、retry模塊。
python3環(huán)境搭建請看主頁
搭建完成后,使用pip安裝retry模塊:
pip?install?retry
2. 客戶端環(huán)境:python3、beautifulsoup4模塊、retry模塊
這里演示一下windows怎么安裝python3和模塊。
windows版python3地址:ccccc://xxx.python.org/ftp/python/3.6.5/python-3.6.5-amd64.exe
直接打開安裝,記得把下圖箭頭的地方勾上:
?

裝完了win+R運行cmd,打開命令提示符窗口,輸入python -V。有如下回顯表示成功:
?

然后我們更新一下pip版本到10.0.1,默認的是9.0.3:
python?-m?pip?install?--upgrade?pip
安裝retry和beautifulsoup4模塊
pip?install?retry
pip?install?beautifulsoup4
?


?
二、程序運行
1.服務端
服務端運行在服務器地址上,使用以下命令即可下載運行。
wget?ccccc://xxx.27server.zzz/shell/ddns_server.py?;
python3?ddns_server.py
如圖,程序運行后輸入上一篇文章你綁定的域名和反代理的端口號,程序會實時監(jiān)聽。
?

2. 客戶端
客戶端以windows為例:
程序地址:ccccc://xxx.27server.zzz/shell/ddns_client.py
將下載好的程序放到D盤根目錄,然后打開cmd執(zhí)行以下命令:
d:
python?ddns_client.py
如圖,程序運行后輸入服務端的地址,即可開始工作:
?

這樣我們就實現(xiàn)了ddns了。當運行在內(nèi)網(wǎng)主機上的客戶端檢測到自己的公網(wǎng)IP變更,則會主動把變更后的IP發(fā)送給云服務器上的服務端,服務端檢測無誤后,將地址寫入nginx的配置文件。無論家庭的公網(wǎng)IP怎么變化,都可以正確指向。
運行截圖(中間重啟了光貓):
?

我們通過socket隨便發(fā)個不是IP地址的文本給服務端:
?

服務端只會接受正確的IP地址格式,并寫入配置文件,防止出錯。
三、源碼
?
#coding=utf-8
import?timeimport?socketfrom?retry?import?retryimport?os
os.system('clear')
server_name=str(input('輸入你的網(wǎng)址:'))
port=int(input('輸入反代理端口號(1-65535):'))if?port?>?65535:
print('端口不合fa!')
exit()elif?port?<1:
print('端口不合fa!')
exit()
?
@retry()def?recv_ip():
sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_TCP)
addr=('0.0.0.0',8888)
sk.bind(addr)
sk.listen(1)
conn,addr=sk.accept()
global?new_ip
new_ip=conn.recv(30).decode()
#sk.sendto(send_data,addr)
sk.close()
conn.close()
?
if?len(new_ip)>15:
?
print('地址不合fa!')
?
elif?len(new_ip)<8;
?
print('xxx')
?
else:
?
print("客戶機公網(wǎng)地址變更:",new_ip)
?
def?write_to():
proxy='server{\nlisten?80;\nserver_name?xxx.27server.com;\nlocation?/?{\n????proxy_pass?cccc://'+new_ip+':'+str(port)+';\n}?\n?access_log?off;\n???}';
os.remove('/usr/local/nginx/conf/vhost/'+server_name+'.conf')
f=open('/usr/local/nginx/conf/vhost/'+server_name+'.conf','w',encoding='utf-8')
f.write(proxy)
f.close()
print("----寫入配置文件成功----")
os.system('service?nginx?restart')
print("已生效,當前反代理規(guī)則為:"+new_ip+':'+str(port))
print('\n------繼續(xù)監(jiān)聽ing..------')
?
print("開始監(jiān)聽客戶機")
recv_ip()
write_to()
?
i=0while?i==0:
time.sleep(5)
recv_ip()
if?new_ip?==?None:
print('地址不能為空!')
continue
elif?new_ip==[]:
print('禁止元素!')
continue
elif?len(new_ip)?>15:
print('地址過長!')
continue
elif?len(new_ip)<8:
print('非fa地址!')
continue
else:
write_to()
2. client端
#coding=utf-8#author:aixi#blog:ccccc://xxx.27server.zzz/
import?urllib.requestfrom?bs4?import?BeautifulSoupimport?socketimport?timefrom?urllib.error?import?URLErrorfrom?retry?import?retry
?
ip_addr=str(input('輸入服務端IP:'))
ip_port=8888#ip_port=int(input('輸入服務端端口(1-65535):'))#if?ip_port?>?65535:#????print('端口不合fa!')#????exit()#elif?ip_port?<1:#????print('端口不合法!')#????exit()
@retry()def?get_ip():
url?=?'cccc://xxx.net.cn/static/customercare/yourip.asp'
req?=?urllib.request.Request(url)
rsp=urllib.request.urlopen(req)
html=rsp.read().decode('utf-8',"ignore")
html=BeautifulSoup(html,'html.parser')
iph2=html.h2
global?ip
ip=iph2.get_text()
#print("你的公網(wǎng)IP是:",ip)
@retry()def?send_ip():#????ip_addr='alish02.ssrcn.me'
addr=(ip_addr,ip_port)
sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_TCP)
sk.connect(addr)
sk.send(ip.encode())
sk.close()
print("\n----開始偵測本機公網(wǎng)IP地址----")
get_ip()
send_ip()
?
i=0while?i?==?0:
get_ip()
print?("當前公網(wǎng)IP:",ip)
tmp1_ip=ip#????print("tmp1_ip:",tmp1_ip)
print("------休息30秒------")
time.sleep(30)
get_ip()
tmp2_ip=ip#???print("tmp2_ip:",tmp2_ip)
if?tmp1_ip?==?tmp2_ip:
print("########OJBK,地址沒變!########")
else:
ip=tmp2_ip
print("公網(wǎng)地址改變:",ip)
send_ip()
print("同步到遠程服務器成功!")
print("\n########繼續(xù)檢查########")
?
我是艾西,今天的分享就到這里啦希望對有需要的小伙伴有幫助我們下期見
擁有一臺服務器可以做很多有趣的事情!
?