zoukankan      html  css  js  c++  java
  • 我第1个可用的golang小程序

    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, 把代码拉下来,调整一下就达到我想要的要求。

      附上完整代码:

      10s
      config.txt
      package main
      
      import (
        "bitbucket.org/kardianos/service"
        "bitbucket.org/kardianos/osext"
        "encoding/xml"
        "errors"
        "fmt"
        "io"
        "io/ioutil"
        "net/http"
        "os"
        "os/exec"
        "time"
      )
      
      var log service.Logger
      
      func 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
      ", err)
                return
              }
              fmt.Printf("Service "%s" installed.
      ", displayName)
            case "remove":
              err = s.Remove()
              if err != nil {
                fmt.Printf("Failed to remove: %s
      ", err)
                return
              }
              fmt.Printf("Service "%s" removed.
      ", displayName)
            case "run":
              DoWork()
            case "start":
              err = s.Start()
              if err != nil {
                fmt.Printf("Failed to start: %s
      ", err)
                return
              }
              fmt.Printf("Service "%s" started.
      ", displayName)
            case "stop":
              err = s.Stop()
              if err != nil {
                fmt.Printf("Failed to stop: %s
      ", err)
                return
              }
              fmt.Printf("Service "%s" stopped.
      ", 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)
      }
      
      /**
      <timezone xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.earthtools.org/timezone.xsd">
       <version>1.0</version>
       <location>
        <latitude>35.86166</latitude>
        <longitude>104.195397</longitude>
       </location>
       <offset>8</offset>
       <suffix>H</suffix>
       <localtime>21 Apr 2014 23:08:09</localtime>
       <isotime>2014-04-21 23:08:09 +0800</isotime>
       <utctime>2014-04-21 15:08:09</utctime>
       <dst>Unknown</dst>
      </timezone>
      */
      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
      }
      */
      SyncSystemTime.go

      BTW: 由于log打印的日志可以在windows的事件查看器中看到,所以我把WriteLogFile函数注释掉了。

      小程序,小功能,请轻拍,欢迎批评意见。

  • 相关阅读:
    iOS图片拉伸技巧
    Swift和OC混合使用
    【转】动态计算UITableViewCell高度详解
    AutoLayout~Label
    【转】初探 iOS8 中的 Size Class
    Objective-C runtime~
    [转]Objective-C中的类和对象(instance)
    Masonry~
    [转] ios学习--openURL的使用方法
    Autolayout~代码实现
  • 原文地址:https://www.cnblogs.com/net205/p/3685259.html
Copyright © 2011-2022 走看看