ntp.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package netmgrd
  2. import (
  3. "fmt"
  4. "math"
  5. "os/exec"
  6. "sync"
  7. "time"
  8. "github.com/beevik/ntp"
  9. "golang.org/x/sys/unix"
  10. )
  11. var servers = []string{
  12. "210.72.145.44",
  13. "ntp.aliyun.com",
  14. "ntp.ntsc.ac.cn",
  15. }
  16. type ntpResult struct {
  17. t time.Time
  18. d time.Duration
  19. err error
  20. }
  21. func SyncNTPTime() error {
  22. t, err := getAccurateTime(servers, 5*time.Second)
  23. if err != nil {
  24. return err
  25. }
  26. if err := SetSystemTime(t); err != nil {
  27. return err
  28. }
  29. return nil
  30. }
  31. func getAccurateTime(servers []string, timeout time.Duration) (time.Time, error) {
  32. ch := make(chan ntpResult, len(servers))
  33. var wg sync.WaitGroup
  34. wg.Add(len(servers))
  35. for _, s := range servers {
  36. go func(s string) {
  37. defer wg.Done()
  38. resp, err := ntp.QueryWithOptions(s, ntp.QueryOptions{Timeout: timeout})
  39. if err != nil {
  40. ch <- ntpResult{err: err}
  41. return
  42. }
  43. if resp.Stratum == 0 || resp.Time.IsZero() {
  44. ch <- ntpResult{err: fmt.Errorf("invalid ntp response")}
  45. return
  46. }
  47. t := resp.Time.Add(resp.RTT / 2)
  48. d := resp.RootDistance // 最大可能偏差
  49. ch <- ntpResult{t: t, d: d, err: nil}
  50. }(s)
  51. }
  52. go func() {
  53. wg.Wait()
  54. close(ch)
  55. }()
  56. var bestTime time.Time
  57. var bestDist time.Duration = math.MaxInt64
  58. for r := range ch {
  59. if r.err != nil {
  60. continue
  61. }
  62. if r.d < bestDist {
  63. bestDist = r.d
  64. bestTime = r.t
  65. }
  66. }
  67. if bestTime.IsZero() {
  68. return time.Time{}, fmt.Errorf("no valid ntp response")
  69. }
  70. return bestTime, nil
  71. }
  72. var setTimeMu sync.Mutex // 调用SetSystemTime()函数的并发互斥
  73. func SetSystemTime(t time.Time) error {
  74. setTimeMu.Lock()
  75. defer setTimeMu.Unlock()
  76. ts := unix.NsecToTimespec(t.UnixNano())
  77. if err := unix.ClockSettime(unix.CLOCK_REALTIME, &ts); err != nil {
  78. return err
  79. }
  80. _ = exec.Command("hwclock", "-w").Run()
  81. return nil
  82. }