ntp.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. --- 模块功能:网络授时.
  2. -- 重要提醒!!!!!!
  3. -- 本功能模块采用多个免费公共的NTP服务器来同步时间
  4. -- 并不能保证任何时间任何地点都能百分百同步到正确的时间
  5. -- 所以,如果用户项目中的业务逻辑严格依赖于时间同步功能
  6. -- 则不要使用使用本功能模块,建议使用自己的应用服务器来同步时间
  7. -- 参考 http://ask.openluat.com/article/912 加深对授时功能的理解
  8. -- @module ntp
  9. -- @author openLuat
  10. -- @license MIT
  11. -- @copyright openLuat
  12. -- @release 2017.10.21
  13. require "misc"
  14. require "socket"
  15. require "utils"
  16. require "log"
  17. local sbyte, ssub = string.byte, string.sub
  18. module(..., package.seeall)
  19. -- NTP服务器域名集合
  20. local timeServer = {
  21. "cn.pool.ntp.org",
  22. "edu.ntp.org.cn",
  23. "cn.ntp.org.cn",
  24. "s2c.time.edu.cn",
  25. "time1.aliyun.com",
  26. "tw.pool.ntp.org",
  27. "0.cn.pool.ntp.org",
  28. "0.tw.pool.ntp.org",
  29. "1.cn.pool.ntp.org",
  30. "1.tw.pool.ntp.org",
  31. "3.cn.pool.ntp.org",
  32. "3.tw.pool.ntp.org",
  33. }
  34. -- 同步超时等待时间
  35. local NTP_TIMEOUT = 8000
  36. -- 同步是否完成标记
  37. local ntpEnd = false
  38. --- 获取NTP服务器地址列表
  39. -- @return table,服务器地址列表
  40. -- @usage local addtable = ntp.getServers()
  41. function getServers()
  42. return timeServer
  43. end
  44. --- 设置NTP服务器地址列表
  45. -- @param st,tab类型,服务器地址列表
  46. -- @return 无
  47. -- @usage ntp.getServers({"1edu.ntp.org.cn","cn.ntp.org.cn"})
  48. function setServers(st)
  49. timeServer = st
  50. end
  51. --- NTP同步标志
  52. -- @return boole,NTP的同步状态true为成功,fasle为失败
  53. -- @usage local sta = ntp.isEnd()
  54. function isEnd()
  55. return ntpEnd
  56. end
  57. --- 同步时间,每个NTP服务器尝试3次,超时8秒,适用于被任务函数调用
  58. -- @param ts,每隔ts小时同步1次
  59. -- @param fnc,同步成功后回调函数
  60. -- @param fun,同步成功前回调函数
  61. -- @return 无
  62. -- @usage ntp.ntpTime() -- 只同步1次
  63. -- @usage ntp.ntpTime(1) -- 1小时同步1次
  64. -- @usage ntp.ntpTime(nil,fnc) -- 只同步1次,同步成功后执行fnc()
  65. -- @usage ntp.ntpTime(24,fnc) -- 24小时同步1次,同步成功后执行fnc()
  66. function ntpTime(ts, fnc, fun)
  67. local rc, data, ntim
  68. ntpEnd = false
  69. while true do
  70. local tUnusedSvr = {}
  71. for i = 1, #timeServer do
  72. tUnusedSvr[i] = timeServer[i]
  73. end
  74. for i = 1, #timeServer do
  75. while not socket.isReady() do sys.waitUntil('IP_READY_IND') end
  76. local c = socket.udp()
  77. local idx = rtos.tick() % #tUnusedSvr + 1
  78. if c:connect(tUnusedSvr[idx], "123") then
  79. if c:send(string.fromHex("E30006EC0000000000000000314E31340000000000000000000000000000000000000000000000000000000000000000")) then
  80. rc, data = c:recv(NTP_TIMEOUT)
  81. if rc and #data == 48 then
  82. ntim = os.date("*t", (sbyte(ssub(data, 41, 41)) - 0x83) * 2 ^ 24 + (sbyte(ssub(data, 42, 42)) - 0xAA) * 2 ^ 16 + (sbyte(ssub(data, 43, 43)) - 0x7E) * 2 ^ 8 + (sbyte(ssub(data, 44, 44)) - 0x80) + 1)
  83. if type(fun) == "function" then fun() end
  84. misc.setClock(ntim, fnc)
  85. ntpEnd = true
  86. c:close()
  87. break
  88. end
  89. end
  90. end
  91. local cnt, n, m = #tUnusedSvr, 1
  92. for m = 1, cnt do
  93. if m ~= idx then
  94. tUnusedSvr[n] = tUnusedSvr[m]
  95. n = n + 1
  96. end
  97. end
  98. tUnusedSvr[cnt] = nil
  99. c:close()
  100. sys.wait(1000)
  101. end
  102. if ntpEnd then
  103. sys.publish("NTP_SUCCEED")
  104. log.info("ntp.timeSync is date:", ntim.year .. "/" .. ntim.month .. "/" .. ntim.day .. "," .. ntim.hour .. ":" .. ntim.min .. ":" .. ntim.sec)
  105. if ts == nil or type(ts) ~= "number" then break end
  106. sys.wait(ts * 3600 * 1000)
  107. else
  108. log.warn("ntp.timeSync is error!")
  109. sys.wait(1000)
  110. end
  111. end
  112. end
  113. --- 自动同步时间任务适合独立执行.
  114. -- 重要提醒!!!!!!
  115. -- 本功能模块采用多个免费公共的NTP服务器来同步时间
  116. -- 并不能保证任何时间任何地点都能百分百同步到正确的时间
  117. -- 所以,如果用户项目中的业务逻辑严格依赖于时间同步功能
  118. -- 则不要使用使用本功能模块,建议使用自己的应用服务器来同步时间
  119. -- @return 无
  120. -- @param ts,每隔ts小时同步1次
  121. -- @param fnc,同步成功后回调函数
  122. -- @param fun,同步成功前回调函数
  123. -- @usage ntp.timeSync() -- 只同步1次
  124. -- @usage ntp.timeSync(1) -- 1小时同步1次
  125. -- @usage ntp.timeSync(nil,fnc) -- 只同步1次,同步成功后执行fnc()
  126. -- @usage ntp.timeSync(24,fnc) -- 24小时同步1次,同步成功后执行fnc()
  127. function timeSync(ts, fnc, fun)
  128. sys.taskInit(ntpTime, ts, fnc, fun)
  129. end