您的位置:首页 > 编程语言 > Python开发

Python 路由器IP变更邮件通知

2013-06-01 19:33 603 查看
最近遇到一个问题:实验室内部的网络是通过路由器分配IP的,但是经常又需要通过校园网远程实验室内部的电脑,而路由器的外网IP是由DHCP服务器动态分配的,IP地址无法绑定成静态的。RadminViewer远程的速度比较快,但是没办法穿墙,必须知道直连的IP地址,通过在实验室的路由器上设置转发端口,就可以实现实验室内部多台电脑同时远程。但是由于路由器上IP会变,自然想到在服务器上运行一个程序,每隔一段时间监测下路由器的IP,如果变化,就发送邮件通知。

使用Python编写,由于是一个后台的程序,自然想到要做出服务,就不会有窗口一直显示。将Python程序以Windows 服务方式启动,需要用到pywin32

本来想实现可以获取每一层的IP,因为网络可能经过了多层的IP地址转换。但还不知道怎么做,最后参考了这里的方法后,目前是只能针对TP-Link的路由器获取外网IP,其他路由器没测试过。

后面还可以进一步扩展,实现很多功能,然后可以发邮件通知。使用的时候,需要先安装服务,然后再启动。服务安装后,默认是手动启动,如果需要设置为自动启动,还需要到Windows管理工具,服务设置中,将该服务设置为自动启动。

在开发过程中,可能需要不断调试以检测是否有bug,因此可以使用调试模式,Service debug,这样可以看到print输出的内容,用于测试服务是否能正常运行。

以下是代码

#-*- encoding: utf-8 -*-

#Service install 安装
#Service start   启动
#Service stop    停止
#Service debug   调试
#Service remove  删除

import win32serviceutil
import win32service
import win32event
import smtplib
import time, traceback
import threading
import logging
import win32evtlogutil

class Service(win32serviceutil.ServiceFramework):
_svc_name_ = "IPDetector"
_svc_display_name_ = "IPDetector"
_svc_description_ = "Detect the change status of router IP, and send mail to notify user."
_svc_deps_ = ["EventLog"]
_sleep_time_ = 20 * 60 #时间以秒为单位
_username_ = 'admin'#路由器用户名
_password_ = 'admin'#路由器密码
_routerIP_ = '192.168.1.1'#路由器内部IP
_mail_list_ = [
"mail1@qq.com",
"mail2@qq.com"
]
_currentIP_ = ''

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
print u'Service is running...'

def SvcDoRun(self):
import servicemanager
timer = threading.Timer(self._sleep_time_, self.process())
timer.start()
# Write a 'started' event to the event log...
win32evtlogutil.ReportEvent(self._svc_name_,
servicemanager.PYS_SERVICE_STARTED,
0, # category
servicemanager.EVENTLOG_INFORMATION_TYPE,
(self._svc_name_, ''))
# wait for beeing stopped...
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)

# and write a 'stopped' event to the event log.
win32evtlogutil.ReportEvent(self._svc_name_,
servicemanager.PYS_SERVICE_STOPPED,
0, # category
servicemanager.EVENTLOG_INFORMATION_TYPE,
(self._svc_name_, ''))
return

def SvcStop(self):
  # Before we do anything, tell SCM we are starting the stop process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# And set my event
win32event.SetEvent(self.hWaitStop)
return

def send_mail(self, mail_list, msg):
try:
handle = smtplib.SMTP('smtp.163.com', 25)
handle.login('mail@163.com','password')
for mail in mail_list:
send_msg = "To:" + mail + "\r\nFrom:mail@163.com\r\nSubject: The latest router IP \r\n\r\n"\
+ msg +"\r\n"
handle.sendmail('mail@163.com', mail, send_msg)
handle.close()
return True
except:
print traceback.format_exc()
return False

def getRouterPublicIP(self, username, password, routerIP):
# this provide a way to get public ip address from tp-link
import httplib, re, base64
showErrorMessage = 0

# 192.168.1.1
conn = httplib.HTTPConnection(routerIP)
# set request headers
headers = {"User-Agent": "python host",
"Content-type": "application/x-www-form-urlencoded",
"Authorization": "Basic %s" % base64.encodestring('%s:%s' % (username, password))[:-1],
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-cn,zh;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Accept-Charset": "GB2312,utf-8;q=0.7,*;q=0.7",
"Connection": "keep-alive"}

# get status page
conn.request("GET", "/userRpm/StatusRpm.htm", "", headers)
response = conn.getresponse()
keyword = re.search(' wanPara [^\)]*?\)', response.read())
response.close()
conn.close()

# search the public ip address
found = 0
publicIP = ""
if keyword:
arr = re.findall('([\d]*?,)|(\"[^\"]*?\",)', keyword.group(0))
if arr:
if len(arr) > 3:
publicIP = re.search('(?<=\")[^\"]*?(?=\")', arr[2][1])
if publicIP:
publicIP = publicIP.group(0)
found = 1

if found == 1:
return publicIP
else:
if showErrorMessage == 1:
logging.info('router public ip address not found.')
#print "router public ip address not found."

def process(self):
latestIP = self.getRouterPublicIP(self._username_, self._password_, self._routerIP_)
logging.info('the latest router ip is: ' + latestIP)
#print 'the latest router ip is: ' + latestIP
if self._currentIP_ != latestIP:
_currentIP_ = latestIP
msg = u'The latest router IP is: ' + str(_currentIP_)
print time.strftime('%Y-%m-%d %X',time.localtime(time.time()))
if self.send_mail(self._mail_list_, msg):
logging.info('send mail success')
#print 'send mail success'
else:
#print 'send mail failed'
logging.info('send mail failed')

if __name__ == '__main__':
win32serviceutil.HandleCommandLine(Service)


这是另外一个版本,用于检测所在机器的本地IP和外网IP。

需要发送通知的邮件地址,需要以每行一个保存到当前目录下的mail.txt中,如

mail1@.gmail.com

mai2.@gmail.com

最新的本地IP地址会保存在latestIP.txt中。

IPDetector.py

#-*- encoding: utf-8 -*-
'''
Created on 13-5-31
'''

import smtplib
import time, traceback, sys, os
from email.mime.text import MIMEText

class IPDetector():
def __init__(self):
pass

def send_mail(self, subject, content):
try:
handle = smtplib.SMTP('smtp.163.com', 25)
handle.login('mail@163.com', 'password')
mail_list = self.getMailList()
time_str = time.strftime('%Y-%m-%d %X', time.localtime(time.time()))
msg = '<html><body>' + content + "<br><br><span style='color:#999;font-size:"\
+ "10px;font-family:Verdana;'>" \
+ time_str + " by servme</span>"+'</body></html>'
send_msg = MIMEText(msg, 'html', 'utf-8')
send_msg['Subject'] = subject

for mail in mail_list:
handle.sendmail('servme@163.com', mail, send_msg.as_string())
handle.close()
return True
except:
print traceback.format_exc()
return False

#读写最新IP信息的文件
def operIPFile(self, mode, data):
#获取脚本路径
path = sys.path[0]
#判断为脚本文件还是py2exe编译后的文件,如果是脚本文件,则返回的是脚本的目录,
#如果是py2exe编译后的文件,则返回的是编译后的文件路径
if os.path.isfile(path):
path = os.path.dirname(path)

if mode == 'read':
file = open(path + u'\latestIP.txt')
line = file.readline()
file.close()
return line
else:
file = open(path + u'\latestIP.txt', 'w')
file.write(data)

def getMailList(self):
mailList = []
#获取脚本路径
path = sys.path[0]
#判断为脚本文件还是py2exe编译后的文件,如果是脚本文件,则返回的是脚本的目录,
#如果是py2exe编译后的文件,则返回的是编译后的文件路径
if os.path.isfile(path):
path = os.path.dirname(path)
file = open(path + u'\mail.txt')
while 1:
line = file.readline()
if not line:
break
mailList.append(line)

file.close()
return mailList

def getLocalPCIP(self):
import socket
localIP = socket.gethostbyname(socket.gethostname()) #得到本地ip
print localIP

import re, urllib2
#获取外网IP
class GetExtIP:
def getIP(self):
try:
extIP = self.visit("http://www.ip138.com/ip2city.asp")
except:
try:
extIP = self.visit("http://www.bliao.com/ip.phtml")
except:
try:
extIP = self.visit("http://www.whereismyip.com/")
except:
extIP = "So sorry!!!"
return extIP

def visit(self, url):
opener = urllib2.urlopen(url)
if url == opener.geturl():
str = opener.read()
else:
str = ''
return re.search('\d+\.\d+\.\d+\.\d+', str).group(0)

externalIP = GetExtIP().getIP()
print externalIP
return localIP, externalIP

#取本地IP
def process(self):
localIP, externalIP = self.getLocalPCIP()
currentIP = self.operIPFile('read', None)
if currentIP != localIP:
self.operIPFile('write', localIP)
time_str = time.strftime('%Y-%m-%d %X', time.localtime(time.time()))
import socket
hostname = socket.gethostname()
print hostname
content = 'Host Name: '+ hostname + '<br>' \
+ 'Local IP address: ' + localIP + '<br>' \
+ 'External IP address: ' + externalIP + '<br>'
subject = "The IP address of " + hostname + " has Changed"
if self.send_mail(subject, content):
print time_str + ' send mail success'
else:
print time_str + ' send mail failed'
else:
print 'The IP address is same with the last detection'

if __name__=='__main__':
ipDetector = IPDetector()
sleep_time = 20 * 60 #时间以秒为单位
while True:
ipDetector.process()
time.sleep(sleep_time)


IPService.py

#-*- encoding: utf-8 -*-
'''
Created on 13-6-1
'''
#IPService install 安装
#IPService start   启动
#IPService stop    停止
#IPService debug   调试
#IPService remove  删除

import win32serviceutil
import win32service
import win32event
import threading
import win32evtlogutil
import time

class Service(win32serviceutil.ServiceFramework):
_svc_name_ = "IPDetector"
_svc_display_name_ = "IPDetector"
_svc_description_ = "Detect the change status of IP, and send mail to notify user."
_svc_deps_ = ["EventLog"]
_sleep_time_ = 20 * 60 #时间以秒为单位

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
print 'Service is running...'

def SvcDoRun(self):
#        import servicemanager
#        from IPDetector import IPDetector
#        ipDetector = IPDetector()
#        timer = threading.Timer(self._sleep_time_, ipDetector.process())
#        timer.start()
#
#        # Write a 'started' event to the event log...
#        win32evtlogutil.ReportEvent(self._svc_name_,
#            servicemanager.PYS_SERVICE_STARTED,
#            0, # category
#            servicemanager.EVENTLOG_INFORMATION_TYPE,
#            (self._svc_name_, ''))
#
#        # wait for beeing stopped...
#        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
#
#        # and write a 'stopped' event to the event log.
#        win32evtlogutil.ReportEvent(self._svc_name_,
#            servicemanager.PYS_SERVICE_STOPPED,
#            0, # category
#            servicemanager.EVENTLOG_INFORMATION_TYPE,
#            (self._svc_name_, ''))

#----------------------------------------------------------------
import servicemanager
# Make entry in the event log that this service started
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, '')
)
from IPDetector import IPDetector
ipDetector = IPDetector()
# Set an amount of time to wait (in milliseconds) between runs
self.timeout = 100
while 1:
# Wait for service stop signal, if I timeout, loop again
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
# Stop signal encountered
break
else:
# Put your code here
ipDetector.process()
time.sleep(self._sleep_time_)
# Only return from SvcDoRun when you wish to stop
return
#-----------------------------------------------------------------

def SvcStop(self):
# Before we do anything, tell SCM we are starting the stop process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# And set my event
win32event.SetEvent(self.hWaitStop)

if __name__ == '__main__':
win32serviceutil.HandleCommandLine(Service)


参考资料

http://www.cnblogs.com/talywy/archive/2013/03/07/SynctimeTool.html

http://www.oschina.net/code/snippet_244244_9744

http://blog.csdn.net/verysmall/article/details/7161256

http://blog.sina.com.cn/s/blog_633b6d790100g4tu.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: