热爱技术
专注分享

将你的电脑变成web服务器之三:使用python3监测公网IP,实现DDNS

上一篇文章中,我们使用Nignx的反向代理和端口转发实现域名访问家里主机上的web了。

https://www.xiaoweigod.com/network/1585.html

由于家庭宽带基本都是动态IP,每当你重启一次光猫,IP地址就会变化一次。当光猫因为停电、故障、维护等原因重启过后,网站就无法访问了。网上基本的解决方法是使用花生壳做DDNS(动态域名解析),但那个需要绑定自己的域名要付费不说,且linux无法使用。于是学了一波python和socket,成功实现了DDNS。

这个程序是一个典型的C/S程序,有客户端和服务端。画张草图来解释下这个python程序的运行原理:

image.png

说明这个程序分为客户端和服务端。客户端运行在内网主机上,服务端运行在云服务器上。客户端会每隔30秒主动检测一次自己的公网IP是否变化,如果地址改变,则会通过socket连接服务端程序,把改变后的地址发送给服务端。服务端接收到地址后,先校验一遍地址是否合法,如果地址OK,那么将地址写入Nginx的反代理配置文件,反代理生效并指向新的内网主机公网地址,从而实现DDNS。

一、程序的使用环境

服务器系统需是centos7,内网主机可以是windows或者centos7

注意:程序是使用python3开发的,不兼容python2。因此如果使用centos7默认自带的python2运行会报错。

1. 服务端环境:python3、retry模块。

python3环境搭建请看:

https://www.xiaoweigod.com/webserver/1603.html

搭建完成后,使用pip安装retry模块:

pip install retry

2. 客户端环境:python3、beautifulsoup4模块、retry模块

这里演示一下windows怎么安装python3和模块。

windows版python3下载地址:https://www.python.org/ftp/python/3.6.5/python-3.6.5-amd64.exe

直接打开安装,记得把下图箭头的地方勾上:

image.png

装完了win+R运行cmd,打开命令提示符窗口,输入python -V。有如下回显表示成功:

image.png

然后我们更新一下pip版本到10.0.1,默认的是9.0.3:

python -m pip install --upgrade pip

安装retry和beautifulsoup4模块

pip install retry
pip install beautifulsoup4

image.png

image.png

二、程序运行

1.服务端

服务端运行在云服务器地址上,使用以下命令即可下载运行。

wget https://www.xiaoweigod.com/shell/ddns_server.py ;
python3 ddns_server.py

如图,程序运行后输入上一篇文章你绑定的域名和反代理的端口号,程序会实时监听。

image.png

2. 客户端

客户端以windows为例:

程序下载地址:https://www.xiaoweigod.com/shell/ddns_client.py

将下载好的程序放到D盘根目录,然后打开cmd执行以下命令:

d:
python ddns_client.py

如图,程序运行后输入服务端的地址,即可开始工作:

image.png

这样我们就实现了ddns了。当运行在内网主机上的客户端检测到自己的公网IP变更,则会主动把变更后的IP发送给云服务器上的服务端,服务端检测无误后,将地址写入nginx的配置文件。无论家庭的公网IP怎么变化,都可以正确指向。

运行截图(中间重启了光猫):

image.png

我们通过socket随便发个不是IP地址的文本给服务端:

image.png

服务端只会接受正确的IP地址格式,并写入配置文件,防止出错。

三、源码

最后把源码附上,大佬不要喷,毕竟才学了点python的皮毛,如果有好的优化建议,欢迎一起来探讨! 交流群:607614097

1. server端

#coding=utf-8

author:xiaowei

blog:https://www.xiaoweigod.com/

import time import socket from retry import retry import os

os.system('clear')

server_name=str(input('输入你的网址:')) port=int(input('输入反代理端口号(1-65535):')) if port > 65535:     print('端口不合法!')     exit() elif port <1:     print('端口不合法!')     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('地址不合法!')

    elif len(new_ip)<8;

        print('玩蛇皮')

    else:

        print("客户机公网地址变更:",new_ip)

def write_to():     proxy='server{\nlisten 80;\nserver_name aaa.xiaoweigod.com;\nlocation / {\n    proxy_pass http://'+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("已生效,当前反代理规则为:"+new_ip+':'+str(port))     print('\n------继续监听ing..------')

print("开始监听客户机") recv_ip() write_to()

i=0 while 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('非法地址!')         continue     else:         write_to()

2. client端

#coding=utf-8
#author:xiaowei
#blog:https://www.xiaoweigod.com/

import urllib.request
from bs4 import BeautifulSoup
import socket
import time
from urllib.error import URLError
from retry import retry

ip_addr=str(input('输入服务端IP:'))
ip_port=8888
#ip_port=int(input('输入服务端端口(1-65535):'))
#if ip_port > 65535:
#    print('端口不合法!')
#    exit()
#elif ip_port <1:
#    print('端口不合法!')
#    exit()

@retry()
def get_ip():
    url = 'http://www.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("你的公网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----开始侦测本机公网IP地址----")
get_ip()
send_ip()

i=0
while i == 0:
    get_ip()
    print ("当前公网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("公网地址改变:",ip)
        send_ip()
        print("同步到远程服务器成功!")
        print("\n########继续检查########")

赞(7) 打赏
未经允许不得转载:小伟博客 » 将你的电脑变成web服务器之三:使用python3监测公网IP,实现DDNS

评论 2

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    好像现在阿里云跟腾讯云都有api吧,感觉好像用过

    aini4715416年前 (2018-06-19)回复
  2. #2

    可以正则过滤掉非IP,这个没必要这样搞。

    3年前 (2021-01-22)回复

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏