设为首页 收藏本站
查看: 1281|回复: 0

[经验分享] 时间同步小工具(Python + Windows Service + NSIS)

[复制链接]

尚未签到

发表于 2015-4-20 09:19:30 | 显示全部楼层 |阅读模式
  家里有台很多年前买的电脑,CMOS电池残废了,经常遇到开机后系统时间被重置的情况,老妈向我反映用起来很不方便。于是身为一个程序员的我想到写个小工具来帮老妈排忧解难。话不多说,小工具需求如下:
功能需求 -- 电脑开机后自动执行时间同步     
非功能需求 -- 安装执行简单,无需安装额外环境

一、代码实现
  基于以上需求,思路如下:访问网络获取北京时间,然后调用命令行来设置系统时间。程序写成Windows Service,并设置为开机自动运行。正好前段时间在学习Python,所以打算用Python来写这个工具。具体代码如下:


DSC0000.gif DSC0001.gif 获取网络时间


1 def getBeijinTime():
2     """
3    获取北京时间
4     """
5     try:
6         conn = httplib.HTTPConnection("www.beijing-time.org")
7         conn.request("GET", "/time.asp")
8         response = conn.getresponse()
9         print response.status, response.reason
10         if response.status == 200:
11             #解析响应的消息
12             result = response.read()
13             logging.debug(result)
14             data = result.split("\r\n")
15             year = data[1][len("nyear")+1 : len(data[1])-1]
16             month = data[2][len("nmonth")+1 : len(data[2])-1]
17             day = data[3][len("nday")+1 : len(data[3])-1]
18             #wday = data[4][len("nwday")+1 : len(data[4])-1]
19             hrs = data[5][len("nhrs")+1 : len(data[5])-1]
20             minute = data[6][len("nmin")+1 : len(data[6])-1]
21             sec = data[7][len("nsec")+1 : len(data[7])-1]
22            
23             beijinTimeStr = "%s/%s/%s %s:%s:%s" % (year, month, day, hrs, minute, sec)
24             beijinTime = time.strptime(beijinTimeStr, "%Y/%m/%d %X")
25             return beijinTime
26     except:
27         logging.exception("getBeijinTime except")
28         return None

同步本地系统时间


1 def syncLocalTime():
2     """
3     同步本地时间
4     """
5     logging.info("current local time is: %d-%d-%d %d:%d:%d" % time.localtime()[:6])
6     
7     beijinTime = getBeijinTime()
8     if beijinTime is None:
9         logging.info("get beijinTime is None, will try again in 30 seconds...")
10         timer = threading.Timer(30.0, syncLocalTime)
11         timer.start();
12     else:
13         logging.info("get beijinTime is: %d-%d-%d %d:%d:%d" % beijinTime[:6])
14            
15         tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec = beijinTime[:6]
16         import os
17         os.system("date %d-%d-%d" % (tm_year, tm_mon, tm_mday))     #设置日期
18         os.system("time %d:%d:%d.0" % (tm_hour, tm_min, tm_sec))    #设置时间
19         logging.info("syncLocalTime complete, current local time: %d-%d-%d %d:%d:%d \n" % time.localtime()[:6])
二、部署安装
  为了让Python程序能以Windows服务的方式运行,需要用到py2exe(用来把Python程序编译成exe)和Python Win32 Extensions 。(py2exe把Python代码编译成Winodws服务时依赖此组件)下载并安装这两个组件。安装完毕后,在Python的安装目录下找到py2exe的Windows Service示例({PythonRoot}\Lib\site-packages\py2exe\samples\advanced\MyService.py)。然后仿照这个示例将上面的代码完善一下。


Windows服务示例


1 import win32serviceutil
2 import win32service
3 import win32event
4 import win32evtlogutil
5
6 class SynctimeService(win32serviceutil.ServiceFramework):
7     _svc_name_ = "Synctime"
8     _svc_display_name_ = "Synctime"
9     _svc_description_ = "Synchronize local system time with beijin time"
10     _svc_deps_ = ["EventLog"]
11     
12     def __init__(self, args):
13         win32serviceutil.ServiceFramework.__init__(self, args)
14         self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
15
16     def SvcStop(self):
17         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
18         win32event.SetEvent(self.hWaitStop)
19
20     def SvcDoRun(self):
21         import servicemanager
22           
23         # Write a 'started' event to the event log...
24         win32evtlogutil.ReportEvent(self._svc_name_,
25                                     servicemanager.PYS_SERVICE_STARTED,
26                                     0, # category
27                                     servicemanager.EVENTLOG_INFORMATION_TYPE,
28                                     (self._svc_name_, ''))
29
30         # wait for beeing stopped...
31         win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
32
33         # and write a 'stopped' event to the event log.
34         win32evtlogutil.ReportEvent(self._svc_name_,
35                                     servicemanager.PYS_SERVICE_STOPPED,
36                                     0, # category
37                                     servicemanager.EVENTLOG_INFORMATION_TYPE,
38                                     (self._svc_name_, ''))   
39
40 if __name__ == '__main__':
41     # Note that this code will not be run in the 'frozen' exe-file!!!
42     win32serviceutil.HandleCommandLine(SynctimeService)  
  之后,再编写一个steup.py文件用来生成安装文件。


Setup.py


1 from distutils.core import setup
2 import py2exe
3
4 setup(
5     # The first three parameters are not required, if at least a
6     # 'version' is given, then a versioninfo resource is built from
7     # them and added to the executables.
8     version = "0.0.1",
9     description = "Synchroniz local system time with beijin time",
10     name = "sysctime",
11
12     # targets to build
13     # console = ["synctime.py"],
14     service=["synctime"]
15 )
  编译生成windows程序,如下图:


DSC0002.png   然后在控制台中运行:setup.py py2exe ,一切顺利的话会在当前目录下生成build和dist目录。


DSC0003.png   控制台目录切换到dist目录,找到synctime.exe,在命令行中运行:
  synctime.exe –install (-remove)  安装或移除时间同步服务。
  现在可以运行services.msc查看服务运行情况


DSC0004.png   可以看到服务并没有启动,而且启动方式为手动。在这里可以右击服务选择属性手动把服务启动起来,并且设置为服务自动启动。
  好吧,我承认。这样操作跟上面的需求有点出入了,略显麻烦。为了解决这个问题,自然想到的是用批处理来做。在dist目录下分别建两个批处理文件:


installservice.bat


1 @echo off
2
3 :: 安装windows服务
4 echo 正在安装服务,请稍候...
5 synctime.exe -install
6
7 :: 设置服务自动启动
8 echo 正在启动服务...
9 sc config Synctime start= AUTO
10
11 :: 启动服务
12 sc start Synctime
13
14 echo 服务启动成功, 按任意键继续...
15 pause

removeserivce.bat


1 @echo off
2
3 :: 停止服务
4 echo 正在停止服务,请稍候...
5 sc stop Synctime
6
7 echo 正在卸载服务...
8 :: 删除windows服务
9 synctime.exe -remove
10
11 echo 服务卸载完成,请按任意键继续剩余卸载...
12 pause
  
好了,现在可以把dist打个包发给老妈用了。但是,这样发个一个压缩包,看起来也太不专业了。解决的办法是打一个安装包,把bat脚本打到安装包里,在安装程序时由安装包调用。这里我用的是NISI(使用HM VNISEdit打包向导来生成打包脚本非常方便)。

三、最终安装效果图


DSC0005.png

DSC0006.png

DSC0007.png

DSC0008.png
四、结尾
  遗留的问题:
  1、从上面的截图可以看到,安装程序在调用批处理时会显示出控制台窗口。这个问题我在网上查找资料,NSIS有相关的插件可以隐藏控制台窗口调用bat文件。
  2、我源代码中有写日志文件的操作,但是以Windows服务的方式运行后,日志文件不能写了,不知道有没有好的解决办法。
  3、360 ...真是要人命啊....Orz..
  
  最后附上源代码及时间同步工具安装包
  
  版权说明:本文章版权归本人及博客园共同所有,未经允许请勿用于任何商业用途。转载请标明原文出处:
  http://www.iyunv.com/talywy/archive/2013/03/07/SynctimeTool.html

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58659-1-1.html 上篇帖子: python学习笔记(七)——文件和目录操作 下篇帖子: 【转载】Python ConfigParser的使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表