我第1個可用的golang小程式

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
  1. 為什麼要寫這個程式

  2. 尋找時間同步Api

  3. 編寫同步程式

  4. 封裝成windows service

 

  1. 為什麼要寫這個程式

            一直在關注golang, 從2011年4月配置環境寫了個hello world!(http://weibo.com/1409046677/wr4n3vdYFV), 後來沒再動手寫golang代碼了, 只是關注golang方面的資訊/資訊。去年到今年稍認真的看了一些golang的基礎文法,然後前幾天家裡的台式電腦又開機用了一下,可能是bios電池沒電的原因吧, 總是開機後需要重新設定時間。於是就想不如用golang寫個windows服務自動更新系統時間,就這樣才有了今天這個golang小程式。

            另外可能有人會說使用windows時間同步功能就行了,沒必要麻煩。這裡我的主要目的是突然興趣所使想用golang練手,其次是windows內建的時間同步功能可能由於牆的原因不好使,反正我手動同步都沒有成功過,

  2. 尋找時間同步Api

            搜尋資料時瞭解到Network Time Protocol(NTP)(http://baike.baidu.com/view/60648.htm)能很精準的同步時間,我不要那麼高要求,只是擷取最新時間,更新時間就行,所以得在網上找個可用的能擷取最新時間API,開始擔心牆,想找國內的,百度有一個http://open.baidu.com/special/time/,但是個頁面,不是我想要的,最後確定使用國外的http://www.earthtools.org/timezone-1.1/35.86166/104.195397

  3. 編寫同步程式

            挺簡單的一個小程式,思路就是擷取API資料,取到時間,然後設定到系統時間,由於還不熟悉golang的api,不知道怎樣使用golang來更新系統時間,後來就使用golang調用dos命令來更新。

            在編寫代碼時,明明知道在golang中,大小寫分別表示public和private,但在定義Timezone結構體,裡面的變數使用小寫,導致總是取不到正確的資料,折騰了不少時間。另外為了ISO-8859-1編碼花了點時間找資料。

  4. 封裝成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}*/
  5.  

    BTW: 由於log列印的日誌可以在windows的事件檢視器中看到,所以我把WriteLogFile函數注釋掉了。

    小程式,小功能,請輕拍,歡迎批評意見。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.