博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
时间同步小工具(Python + Windows Service + NSIS)
阅读量:5267 次
发布时间:2019-06-14

本文共 5971 字,大约阅读时间需要 19 分钟。

家里有台很多年前买的电脑,CMOS电池残废了,经常遇到开机后系统时间被重置的情况,老妈向我反映用起来很不方便。于是身为一个程序员的我想到写个小工具来帮老妈排忧解难。话不多说,小工具需求如下:

功能需求 -- 电脑开机后自动执行时间同步
非功能需求 -- 安装执行简单,无需安装额外环境

一、代码实现

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

获取网络时间
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.reason10         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 os17         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服务的方式运行,需要用到(用来把Python程序编译成exe)和 。(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 servicemanager22           23         # Write a 'started' event to the event log...24         win32evtlogutil.ReportEvent(self._svc_name_,25                                     servicemanager.PYS_SERVICE_STARTED,26                                     0, # category27                                     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, # category37                                     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 build13     # console = ["synctime.py"],14     service=["synctime"]15 )

编译生成windows程序,如下图:

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

控制台目录切换到dist目录,找到synctime.exe,在命令行中运行:

synctime.exe –install (-remove)  安装或移除时间同步服务。

现在可以运行services.msc查看服务运行情况

可以看到服务并没有启动,而且启动方式为手动。在这里可以右击服务选择属性手动把服务启动起来,并且设置为服务自动启动。

好吧,我承认。这样操作跟上面的需求有点出入了,略显麻烦。为了解决这个问题,自然想到的是用批处理来做。在dist目录下分别建两个批处理文件:

installservice.bat
1 @echo off 2  3 :: 安装windows服务 4 echo 正在安装服务,请稍候... 5 synctime.exe -install 6  7 :: 设置服务自动启动 8 echo 正在启动服务... 9 sc config Synctime start= AUTO10 11 :: 启动服务12 sc start Synctime13 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 -remove10 11 echo 服务卸载完成,请按任意键继续剩余卸载...12 pause

好了,现在可以把dist打个包发给老妈用了。但是,这样发个一个压缩包,看起来也太不专业了。解决的办法是打一个安装包,把bat脚本打到安装包里,在安装程序时由安装包调用。这里我用的是NISI(使用HM VNISEdit打包向导来生成打包脚本非常方便)。

三、最终安装效果图

四、结尾

遗留的问题:

1、从上面的截图可以看到,安装程序在调用批处理时会显示出控制台窗口。这个问题我在网上查找资料,NSIS有相关的插件可以隐藏控制台窗口调用bat文件。

2、我源代码中有写日志文件的操作,但是以Windows服务的方式运行后,日志文件不能写了,不知道有没有好的解决办法。

3、360 ...真是要人命啊....Orz..

 

最后附上及时间同步工具

 

版权说明:本文章版权归本人及博客园共同所有,未经允许请勿用于任何商业用途。转载请标明原文出处:

转载于:https://www.cnblogs.com/talywy/archive/2013/03/07/SynctimeTool.html

你可能感兴趣的文章
通过FTP无法删除文件
查看>>
Wannafly挑战赛1 C MMSet2 虚树
查看>>
Linux进程间通信方式--信号,管道,消息队列,信号量,共享内存
查看>>
PHP,JAVA,NET 开发比较
查看>>
简单的介绍自己
查看>>
一个重写的ToString()方法引发的装箱
查看>>
第一天,浅玩 Cassandra 集群配置及启动
查看>>
为自己的教育投资,老师带会更快,不然也就没有老师存在了
查看>>
划分树--区间第K元素模板
查看>>
JavaScript归并方法reduce()和reduceRight()
查看>>
js 循环BUG
查看>>
中世纪开始在英语里也用作Affrike指非洲
查看>>
九、数组以及排序和查找
查看>>
构建之法阅读心得(八)
查看>>
每次启动word 2007时都要进行安装配置的解决方法
查看>>
Hello 2018 A,B,C,D
查看>>
gym-101343B-So You Think You Can Count?
查看>>
每周总结15
查看>>
OpenCV_用鼠标在窗口画方形
查看>>
POJ1221(整数划分)
查看>>