Python 路由器IP变更邮件通知

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

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

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

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

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

 

 以下是代码

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

  2 

  3 #Service install 安装

  4 #Service start   启动

  5 #Service stop    停止

  6 #Service debug   调试

  7 #Service remove  删除

  8 

  9 import win32serviceutil

 10 import win32service

 11 import win32event

 12 import smtplib

 13 import time, traceback

 14 import threading

 15 import logging

 16 import win32evtlogutil

 17 

 18 class Service(win32serviceutil.ServiceFramework):

 19     _svc_name_ = "IPDetector"

 20     _svc_display_name_ = "IPDetector"

 21     _svc_description_ = "Detect the change status of router IP, and send mail to notify user."

 22     _svc_deps_ = ["EventLog"]

 23     _sleep_time_ = 20 * 60 #时间以秒为单位

 24     _username_ = 'admin'#路由器用户名

 25     _password_ = 'admin'#路由器密码

 26     _routerIP_ = '192.168.1.1'#路由器内部IP

 27     _mail_list_ = [

 28         "[email protected]",

 29         "[email protected]"

 30         ]

 31     _currentIP_ = ''

 32 

 33     def __init__(self, args):

 34         win32serviceutil.ServiceFramework.__init__(self, args)

 35         self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)

 36         print u'Service is running...'

 37 

 38     def SvcDoRun(self):

 39         import servicemanager

 40         timer = threading.Timer(self._sleep_time_, self.process())

 41         timer.start()

 42         # Write a 'started' event to the event log...

 43         win32evtlogutil.ReportEvent(self._svc_name_,

 44                                     servicemanager.PYS_SERVICE_STARTED,

 45                                     0, # category

 46                                     servicemanager.EVENTLOG_INFORMATION_TYPE,

 47                                     (self._svc_name_, ''))

 48         # wait for beeing stopped...

 49         win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)

 50 

 51         # and write a 'stopped' event to the event log.

 52         win32evtlogutil.ReportEvent(self._svc_name_,

 53                                     servicemanager.PYS_SERVICE_STOPPED,

 54                                     0, # category

 55                                     servicemanager.EVENTLOG_INFORMATION_TYPE,

 56                                     (self._svc_name_, ''))

 57         return

 58 

 59     def SvcStop(self):

 60       # Before we do anything, tell SCM we are starting the stop process.

 61         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

 62         # And set my event

 63         win32event.SetEvent(self.hWaitStop)

 64         return

 65 

 66     def send_mail(self, mail_list, msg):

 67         try:

 68             handle = smtplib.SMTP('smtp.163.com', 25)

 69             handle.login('[email protected]','password')

 70             for mail in mail_list:

 71                 send_msg = "To:" + mail + "\r\nFrom:[email protected]\r\nSubject: The latest router IP \r\n\r\n"\

 72                            + msg +"\r\n"

 73                 handle.sendmail('[email protected]', mail, send_msg)

 74             handle.close()

 75             return True

 76         except:

 77             print traceback.format_exc()

 78             return False

 79 

 80     def getRouterPublicIP(self, username, password, routerIP):

 81         # this provide a way to get public ip address from tp-link

 82         import httplib, re, base64

 83         showErrorMessage = 0

 84 

 85         # 192.168.1.1

 86         conn = httplib.HTTPConnection(routerIP)

 87         # set request headers

 88         headers = {"User-Agent": "python host",

 89                    "Content-type": "application/x-www-form-urlencoded",

 90                    "Authorization": "Basic %s" % base64.encodestring('%s:%s' % (username, password))[:-1],

 91                    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",

 92                    "Accept-Language": "zh-cn,zh;q=0.5",

 93                    "Accept-Encoding": "gzip, deflate",

 94                    "Accept-Charset": "GB2312,utf-8;q=0.7,*;q=0.7",

 95                    "Connection": "keep-alive"}

 96 

 97         # get status page

 98         conn.request("GET", "/userRpm/StatusRpm.htm", "", headers)

 99         response = conn.getresponse()

100         keyword = re.search(' wanPara [^\)]*?\)', response.read())

101         response.close()

102         conn.close()

103 

104         # search the public ip address

105         found = 0

106         publicIP = ""

107         if keyword:

108             arr = re.findall('([\d]*?,)|(\"[^\"]*?\",)', keyword.group(0))

109             if arr:

110                 if len(arr) > 3:

111                     publicIP = re.search('(?<=\")[^\"]*?(?=\")', arr[2][1])

112                     if publicIP:

113                         publicIP = publicIP.group(0)

114                         found = 1

115 

116         if found == 1:

117             return publicIP

118         else:

119             if showErrorMessage == 1:

120                 logging.info('router public ip address not found.')

121                 #print "router public ip address not found."

122 

123     def process(self):

124         latestIP = self.getRouterPublicIP(self._username_, self._password_, self._routerIP_)

125         logging.info('the latest router ip is: ' + latestIP)

126         #print 'the latest router ip is: ' + latestIP

127         if self._currentIP_ != latestIP:

128             _currentIP_ = latestIP

129             msg = u'The latest router IP is: ' + str(_currentIP_)

130             print time.strftime('%Y-%m-%d %X',time.localtime(time.time()))

131             if self.send_mail(self._mail_list_, msg):

132                 logging.info('send mail success')

133                 #print 'send mail success'

134             else:

135                 #print 'send mail failed'

136                 logging.info('send mail failed')

137 

138 if __name__ == '__main__':

139     win32serviceutil.HandleCommandLine(Service)

 

 

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

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

[email protected]

[email protected]

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

 

IPDetector.py

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

  2 '''

  3 Created on 13-5-31

  4 '''

  5 

  6 import smtplib

  7 import time, traceback, sys, os

  8 from email.mime.text import MIMEText

  9 

 10 class IPDetector():

 11     def __init__(self):

 12         pass

 13 

 14     def send_mail(self, subject, content):

 15         try:

 16             handle = smtplib.SMTP('smtp.163.com', 25)

 17             handle.login('[email protected]', 'password')

 18             mail_list = self.getMailList()

 19             time_str = time.strftime('%Y-%m-%d %X', time.localtime(time.time()))

 20             msg = '<html><body>' + content + "<br><br><span style='color:#999;font-size:"\

 21                         + "10px;font-family:Verdana;'>" \

 22                         + time_str + " by servme</span>"+'</body></html>'

 23             send_msg = MIMEText(msg, 'html', 'utf-8')

 24             send_msg['Subject'] = subject

 25 

 26             for mail in mail_list:

 27                 handle.sendmail('[email protected]', mail, send_msg.as_string())

 28             handle.close()

 29             return True

 30         except:

 31             print traceback.format_exc()

 32             return False

 33 

 34     #读写最新IP信息的文件

 35     def operIPFile(self, mode, data):

 36         #获取脚本路径

 37         path = sys.path[0]

 38         #判断为脚本文件还是py2exe编译后的文件,如果是脚本文件,则返回的是脚本的目录,

 39         #如果是py2exe编译后的文件,则返回的是编译后的文件路径

 40         if os.path.isfile(path):

 41             path = os.path.dirname(path)

 42 

 43         if mode == 'read':

 44             file = open(path + u'\latestIP.txt')

 45             line = file.readline()

 46             file.close()

 47             return line

 48         else:

 49             file = open(path + u'\latestIP.txt', 'w')

 50             file.write(data)

 51 

 52     def getMailList(self):

 53         mailList = []

 54         #获取脚本路径

 55         path = sys.path[0]

 56         #判断为脚本文件还是py2exe编译后的文件,如果是脚本文件,则返回的是脚本的目录,

 57         #如果是py2exe编译后的文件,则返回的是编译后的文件路径

 58         if os.path.isfile(path):

 59             path = os.path.dirname(path)

 60         file = open(path + u'\mail.txt')

 61         while 1:

 62             line = file.readline()

 63             if not line:

 64                 break

 65             mailList.append(line)

 66 

 67         file.close()

 68         return mailList

 69 

 70     def getLocalPCIP(self):

 71         import socket

 72         localIP = socket.gethostbyname(socket.gethostname()) #得到本地ip

 73         print localIP

 74 

 75         import re, urllib2

 76         #获取外网IP

 77         class GetExtIP:

 78             def getIP(self):

 79                 try:

 80                     extIP = self.visit("http://www.ip138.com/ip2city.asp")

 81                 except:

 82                     try:

 83                         extIP = self.visit("http://www.bliao.com/ip.phtml")

 84                     except:

 85                         try:

 86                             extIP = self.visit("http://www.whereismyip.com/")

 87                         except:

 88                             extIP = "So sorry!!!"

 89                 return extIP

 90 

 91             def visit(self, url):

 92                 opener = urllib2.urlopen(url)

 93                 if url == opener.geturl():

 94                     str = opener.read()

 95                 else:

 96                     str = ''

 97                 return re.search('\d+\.\d+\.\d+\.\d+', str).group(0)

 98 

 99         externalIP = GetExtIP().getIP()

100         print externalIP

101         return localIP, externalIP

102 

103     #取本地IP

104     def process(self):

105         localIP, externalIP = self.getLocalPCIP()

106         currentIP = self.operIPFile('read', None)

107         if currentIP != localIP:

108             self.operIPFile('write', localIP)

109             time_str = time.strftime('%Y-%m-%d %X', time.localtime(time.time()))

110             import socket

111             hostname = socket.gethostname()

112             print hostname

113             content = 'Host Name: '+ hostname + '<br>' \

114                         + 'Local IP address: ' + localIP + '<br>' \

115                         + 'External IP address: ' + externalIP + '<br>'

116             subject = "The IP address of " + hostname + " has Changed"

117             if self.send_mail(subject, content):

118                 print time_str + ' send mail success'

119             else:

120                 print time_str + ' send mail failed'

121         else:

122             print 'The IP address is same with the last detection'

123 

124 if __name__=='__main__':

125     ipDetector = IPDetector()

126     sleep_time = 20 * 60 #时间以秒为单位

127     while True:

128         ipDetector.process()

129         time.sleep(sleep_time)

 

IPService.py

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

 2 '''

 3 Created on 13-6-1

 4 '''

 5 #IPService install 安装

 6 #IPService start   启动

 7 #IPService stop    停止

 8 #IPService debug   调试

 9 #IPService remove  删除

10 

11 import win32serviceutil

12 import win32service

13 import win32event

14 import threading

15 import win32evtlogutil

16 import time

17 

18 class Service(win32serviceutil.ServiceFramework):

19     _svc_name_ = "IPDetector"

20     _svc_display_name_ = "IPDetector"

21     _svc_description_ = "Detect the change status of IP, and send mail to notify user."

22     _svc_deps_ = ["EventLog"]

23     _sleep_time_ = 20 * 60 #时间以秒为单位

24 

25     def __init__(self, args):

26         win32serviceutil.ServiceFramework.__init__(self, args)

27         self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)

28         print 'Service is running...'

29 

30     def SvcDoRun(self):

31 #        import servicemanager

32 #        from IPDetector import IPDetector

33 #        ipDetector = IPDetector()

34 #        timer = threading.Timer(self._sleep_time_, ipDetector.process())

35 #        timer.start()

36 #

37 #        # Write a 'started' event to the event log...

38 #        win32evtlogutil.ReportEvent(self._svc_name_,

39 #            servicemanager.PYS_SERVICE_STARTED,

40 #            0, # category

41 #            servicemanager.EVENTLOG_INFORMATION_TYPE,

42 #            (self._svc_name_, ''))

43 #

44 #        # wait for beeing stopped...

45 #        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)

46 #

47 #        # and write a 'stopped' event to the event log.

48 #        win32evtlogutil.ReportEvent(self._svc_name_,

49 #            servicemanager.PYS_SERVICE_STOPPED,

50 #            0, # category

51 #            servicemanager.EVENTLOG_INFORMATION_TYPE,

52 #            (self._svc_name_, ''))

53 

54         #----------------------------------------------------------------

55         import servicemanager

56         # Make entry in the event log that this service started

57         servicemanager.LogMsg(

58             servicemanager.EVENTLOG_INFORMATION_TYPE,

59             servicemanager.PYS_SERVICE_STARTED,

60             (self._svc_name_, '')

61         )

62         from IPDetector import IPDetector

63         ipDetector = IPDetector()

64         # Set an amount of time to wait (in milliseconds) between runs

65         self.timeout = 100

66         while 1:

67             # Wait for service stop signal, if I timeout, loop again

68             rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)

69             # Check to see if self.hWaitStop happened

70             if rc == win32event.WAIT_OBJECT_0:

71                 # Stop signal encountered

72                 break

73             else:

74                 # Put your code here

75                 ipDetector.process()

76                 time.sleep(self._sleep_time_)

77                 # Only return from SvcDoRun when you wish to stop

78         return

79         #-----------------------------------------------------------------

80 

81     def SvcStop(self):

82         # Before we do anything, tell SCM we are starting the stop process.

83         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

84         # And set my event

85         win32event.SetEvent(self.hWaitStop)

86 

87 if __name__ == '__main__':

88     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

你可能感兴趣的:(python)