封裝成windows service
關於編寫windows service,開始搜尋到資料http://sanatgersappa.blogspot.com/2013/07/windows-service-with-go-easy-way.html (需要翻牆),感覺NSSM(http://nssm.cc/)挺方便的,考慮使用NSSM程式,使用NSSM把exe程式註冊成windows服務,命令:
nssm install MyService d:\MyService.exe
(where d:\MyService.exe is the full path to the exe file).
我當時就寫了2個批次程式CreateService.bat:
nssm install SyncSystemTimeService %CD%\SyncSystemTim.exe
DeleteService.bat:
sc delete SyncSystemTimeService
windows服務註冊成功了,啟動SyncSystemTimeService服務後,我的程式好像並沒有生效,我懷疑要麼必須使用完整的路徑(不能用%CD%變數), 要麼可能使用%~dp0而不是%CD%(參考資料:http://stackoverflow.com/questions/16255184/how-do-i-find-the-current-directory-of-a-batch-file-and-then-use-it-for-the-pat),後來我沒有繼續查原因,在網上找到了使用golang寫的一個服務程式:http://bitbucket.org/kardianos/service, 把代碼拉下來,調整一下就達到我想要的要求。
附上完整代碼:
config.txt:
10s
SyncSystemTime.go
package mainimport ( "bitbucket.org/kardianos/service" "bitbucket.org/kardianos/osext" "encoding/xml" "errors" "fmt" "io" "io/ioutil" "net/http" "os" "os/exec" "time")var log service.Loggerfunc main() { var name = "SyncSystemTimeService" var displayName = "Sync System Time Service" var desc = "同步更新window時間服務(通過網路擷取最新時間)" var s, err = service.NewService(name, displayName, desc) log = s if err != nil { fmt.Printf("%s unable to start: %s", displayName, err) return } if len(os.Args) > 1 { var err error verb := os.Args[1] switch verb { case "install": err = s.Install() if err != nil { fmt.Printf("Failed to install: %s\n", err) return } fmt.Printf("Service \"%s\" installed.\n", displayName) case "remove": err = s.Remove() if err != nil { fmt.Printf("Failed to remove: %s\n", err) return } fmt.Printf("Service \"%s\" removed.\n", displayName) case "run": DoWork() case "start": err = s.Start() if err != nil { fmt.Printf("Failed to start: %s\n", err) return } fmt.Printf("Service \"%s\" started.\n", displayName) case "stop": err = s.Stop() if err != nil { fmt.Printf("Failed to stop: %s\n", err) return } fmt.Printf("Service \"%s\" stopped.\n", displayName) } return } err = s.Run(func() error { go DoWork() return nil }, func() error { StopWork() return nil }) if err != nil { s.Error(err.Error()) }}func DoWork() { log.Info("I'm Running!") const defaultSchedulingTime = "30m" // minutes schedulingTime := defaultSchedulingTime configFile := "config.txt" configPath, err := osext.ExecutableFolder() if err != nil { log.Warning(err.Error()) } else { configFile = configPath + configFile } log.Info(configFile) timeConfig, err := ioutil.ReadFile(configFile) if err == nil { schedulingTime = string(timeConfig) } else { log.Warning(err.Error()) } timeDuration, err := time.ParseDuration(schedulingTime) if err != nil { log.Warning(err.Error()) timeDuration, err = time.ParseDuration(defaultSchedulingTime) } Go() timer := time.NewTicker(timeDuration) for { select { case <-timer.C: Go() } } select {}}func StopWork() { log.Info("I'm Stopping!")}func Go() { networkTime := GetNetworkTime() SetSystemTime(networkTime)}/**1.035.86166104.1953978H21 Apr 2014 23:08:092014-04-21 23:08:09 +08002014-04-21 15:08:09Unknown*/type Timezone struct { LocalTime string `xml:"localtime"` IsoTime string `xml:"isotime"` UtcTime string `xml:"utctime"`}func charsetReader(charset string, r io.Reader) (io.Reader, error) { if charset == "ISO-8859-1" || charset == "iso-8859-1" { return r, nil } return nil, errors.New("Unsupported character set encoding: " + charset)}func GetNetworkTime() string { const web_service_url = "http://www.earthtools.org/timezone-1.1/35.86166/104.195397" result, err1 := http.Get(web_service_url) if err1 != nil { log.Warning(err1.Error()) return "" } defer result.Body.Close() var timezone Timezone data := xml.NewDecoder(result.Body) data.CharsetReader = charsetReader if err := data.Decode(&timezone); err != nil { return "" } // fmt.Println(timezone.UtcTime) return timezone.UtcTime}func SetSystemTime(dateTime string) { if dateTime == "" { return } currentTime := time.Now().Format("2006-01-02 15:04:05") logContent := currentTime convertTime, err1 := time.Parse("2006-01-02 15:04:05", dateTime) if err1 != nil { log.Warning(err1.Error()) return } convertTime = convertTime.Add(8 * time.Hour) logContent = logContent + " --> " + convertTime.Format("2006-01-02 15:04:05") compareValue := convertTime.Format("2006-01-02 15:04:05") // 如果時間(年月日時分)相同,則不更新 if currentTime[0:len(currentTime)-3] == compareValue[0:len(compareValue)-3] { log.Info("same time, not to update: " + currentTime + " | " + compareValue) return } _, err2 := exec.Command("CMD", "/C", "DATE", convertTime.Format("2006-01-02")).Output() if err2 != nil { log.Error(err2.Error()) } _, err2 = exec.Command("CMD", "/C", "TIME", convertTime.Format("15:04:05")).Output() if err2 != nil { log.Error(err2.Error()) } currentTime = time.Now().Format("2006-01-02 15:04:05") logContent = logContent + " --> " + currentTime log.Info(logContent) // WriteLogFile(logContent)}/*func WriteLogFile(logContent string) error { fileName := "log.txt" file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatal("error opening file: %v", err) return err } defer file.Close() log.SetOutput(file) log.Println(logContent) return nil}*/