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         "mail1@qq.com",
 29         "mail2@qq.com"
 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('mail@163.com','password')
 70             for mail in mail_list:
 71                 send_msg = "To:" + mail + "\r\nFrom:mail@163.com\r\nSubject: The latest router IP \r\n\r\n"\
 72                            + msg +"\r\n"
 73                 handle.sendmail('mail@163.com', 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中,如

mail1@.gmail.com

mai2.@gmail.com

最新的本地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('mail@163.com', '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('servme@163.com', 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

posted @ 2013-06-01 19:33  NaN-Hax  阅读(1653)  评论(1编辑  收藏  举报