最近遇到一个问题:实验室内部的网络是通过路由器分配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 importwin32serviceutil10 importwin32service11 importwin32event12 importsmtplib13 importtime, traceback14 importthreading15 importlogging16 importwin32evtlogutil17
18 classService(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 defSvcDoRun(self):39 importservicemanager40 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,