時間同步小工具(Python + Windows Service + NSIS)


家里有台很多年前買的電腦,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.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程序,如下圖:

然后在控制台中運行: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= 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打包向導來生成打包腳本非常方便)。

三、最終安裝效果圖

四、結尾

遺留的問題:

1、從上面的截圖可以看到,安裝程序在調用批處理時會顯示出控制台窗口。這個問題我在網上查找資料,NSIS有相關的插件可以隱藏控制台窗口調用bat文件。

2、我源代碼中有寫日志文件的操作,但是以Windows服務的方式運行后,日志文件不能寫了,不知道有沒有好的解決辦法。

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

 

最后附上源代碼及時間同步工具安裝包

 

版權說明:本文章版權歸本人及博客園共同所有,未經允許請勿用於任何商業用途。轉載請標明原文出處:

http://www.cnblogs.com/talywy/archive/2013/03/07/SynctimeTool.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM