ntp.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package netmgrd
  2. import (
  3. "fmt"
  4. "os/exec"
  5. "sync"
  6. "time"
  7. "github.com/beevik/ntp"
  8. )
  9. var servers = []string{
  10. "210.72.145.44",
  11. "ntp.aliyun.com",
  12. "ntp.ntsc.ac.cn",
  13. }
  14. type ntpResult struct {
  15. t time.Time
  16. stratum uint8
  17. err error
  18. }
  19. func SyncNTPTime() error {
  20. t, err := getAccurateTime(servers, 5*time.Second)
  21. if err != nil {
  22. return err
  23. }
  24. if err := SetSystemTime(t); err != nil {
  25. return err
  26. }
  27. return nil
  28. }
  29. func getAccurateTime(servers []string, timeout time.Duration) (time.Time, error) {
  30. ch := make(chan ntpResult, len(servers))
  31. var wg sync.WaitGroup
  32. wg.Add(len(servers))
  33. for _, s := range servers {
  34. go func(s string) {
  35. defer wg.Done()
  36. resp, err := ntp.QueryWithOptions(s, ntp.QueryOptions{Timeout: timeout})
  37. if err != nil || resp.Stratum == 0 || resp.Stratum > 5 || resp.Time.IsZero() {
  38. ch <- ntpResult{err: err} // "resp.Stratum"为0(无效服务器)或大于5(精度较低)
  39. return
  40. }
  41. ch <- ntpResult{t: resp.Time, stratum: resp.Stratum}
  42. }(s)
  43. }
  44. go func() {
  45. wg.Wait()
  46. close(ch)
  47. }()
  48. var results []ntpResult
  49. for r := range ch {
  50. if r.err == nil {
  51. results = append(results, r)
  52. }
  53. }
  54. if len(results) == 0 {
  55. return time.Time{}, fmt.Errorf("所有NTP服务器请求失败或无有效时间")
  56. }
  57. // 找最低 Stratum
  58. minStratum := uint8(255)
  59. for _, r := range results {
  60. if r.stratum < minStratum {
  61. minStratum = r.stratum
  62. }
  63. }
  64. // 最低 Stratum 的时间
  65. var bestTimes []time.Time
  66. for _, r := range results {
  67. if r.stratum == minStratum {
  68. bestTimes = append(bestTimes, r.t)
  69. }
  70. }
  71. return bestTimes[0], nil
  72. }
  73. var setTimeMu sync.Mutex // 保证调用 SetSystemTime() 函数的线程安全
  74. func SetSystemTime(t time.Time) error {
  75. setTimeMu.Lock()
  76. defer setTimeMu.Unlock()
  77. cmd := exec.Command("date", "-s", t.Local().Format("2006-01-02 15:04:05"))
  78. output, err := cmd.CombinedOutput()
  79. if err != nil {
  80. return fmt.Errorf("%v, output: %s", err, string(output))
  81. }
  82. return nil
  83. }