| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- --- 模块功能:网络授时.
- -- 重要提醒!!!!!!
- -- 本功能模块采用多个免费公共的NTP服务器来同步时间
- -- 并不能保证任何时间任何地点都能百分百同步到正确的时间
- -- 所以,如果用户项目中的业务逻辑严格依赖于时间同步功能
- -- 则不要使用使用本功能模块,建议使用自己的应用服务器来同步时间
- -- 参考 http://ask.openluat.com/article/912 加深对授时功能的理解
- -- @module ntp
- -- @author openLuat
- -- @license MIT
- -- @copyright openLuat
- -- @release 2017.10.21
- require "misc"
- require "socket"
- require "utils"
- require "log"
- local sbyte, ssub = string.byte, string.sub
- module(..., package.seeall)
- -- NTP服务器域名集合
- local timeServer = {
- "cn.pool.ntp.org",
- "edu.ntp.org.cn",
- "cn.ntp.org.cn",
- "s2c.time.edu.cn",
- "time1.aliyun.com",
- "tw.pool.ntp.org",
- "0.cn.pool.ntp.org",
- "0.tw.pool.ntp.org",
- "1.cn.pool.ntp.org",
- "1.tw.pool.ntp.org",
- "3.cn.pool.ntp.org",
- "3.tw.pool.ntp.org",
- }
- -- 同步超时等待时间
- local NTP_TIMEOUT = 8000
- -- 同步是否完成标记
- local ntpEnd = false
- -- 获取NTP服务器地址列表
- -- @return table,服务器地址列表
- -- @usage local addtable = ntp.getServers()
- function getServers()
- return timeServer
- end
- -- 设置NTP服务器地址列表
- -- @table st,tab类型,服务器地址列表
- -- @return 无
- -- @usage ntp.getServers({"1edu.ntp.org.cn","cn.ntp.org.cn"})
- function setServers(st)
- timeServer = st
- end
- -- NTP同步标志
- -- @return bool,NTP的同步状态true为成功,fasle为失败
- -- @usage local sta = ntp.isEnd()
- function isEnd()
- return ntpEnd
- end
- local sTs,sFnc,sFun
- -- 同步时间,随机每个NTP服务器尝试1次,超时8秒,适用于被任务函数调用
- -- @number ts,每隔ts小时同步1次
- -- @function fnc,同步成功后回调函数
- -- @function fun,同步成功前回调函数
- -- @return nil
- -- @usage ntp.ntpTime() -- 只同步1次
- -- @usage ntp.ntpTime(1) -- 1小时同步1次
- -- @usage ntp.ntpTime(nil,fnc) -- 只同步1次,同步成功后执行fnc()
- -- @usage ntp.ntpTime(24,fnc) -- 24小时同步1次,同步成功后执行fnc()
- function ntpTime(ts, fnc, fun)
- local rc, data, ntim
- local sTs,sFnc,sFun = ts or sTs, fnc or sFnc, fun or sFun
- ntpEnd = false
- while true do
- local tUnusedSvr = {}
- for i = 1, #timeServer do
- tUnusedSvr[i] = timeServer[i]
- end
- for i = 1, #timeServer do
- while not socket.isReady() do sys.waitUntil('IP_READY_IND') end
- local c = socket.udp()
- local idx = rtos.tick() % #tUnusedSvr + 1
- if c:connect(tUnusedSvr[idx], "123") then
- if c:send(string.fromHex("E30006EC0000000000000000314E31340000000000000000000000000000000000000000000000000000000000000000")) then
- rc, data = c:recv(NTP_TIMEOUT)
- if rc and #data == 48 then
- 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)
- if type(sFun) == "function" then sFun() end
- misc.setClock(ntim, sFnc)
- ntpEnd = true
- c:close()
- break
- end
- end
- end
-
- local cnt, n, m = #tUnusedSvr, 1
- for m = 1, cnt do
- if m ~= idx then
- tUnusedSvr[n] = tUnusedSvr[m]
- n = n + 1
- end
- end
- tUnusedSvr[cnt] = nil
-
- c:close()
- sys.wait(1000)
- end
- if ntpEnd then
- sys.publish("NTP_SUCCEED")
- log.info("ntp.timeSync is date:", ntim.year .. "/" .. ntim.month .. "/" .. ntim.day .. "," .. ntim.hour .. ":" .. ntim.min .. ":" .. ntim.sec)
- else
- log.warn("ntp.timeSync is error!")
- end
- if sTs == nil or type(sTs) ~= "number" then break end
- sys.wait(sTs * 3600 * 1000)
- end
- end
- --- ntp同步时间任务.
- -- 重要提醒!!!!!!
- -- 本功能模块采用多个免费公共的NTP服务器来同步时间
- -- 并不能保证任何时间任何地点都能百分百同步到正确的时间
- -- 所以,如果用户项目中的业务逻辑严格依赖于时间同步功能
- -- 则不要使用使用本功能模块,建议使用自己的应用服务器来同步时间
- -- @number[opt=nil] period 调用本接口会立即同步一次;每隔period小时再自动同步1次,nil表示仅同步一次
- -- @function[opt=nil] fnc 同步结束,设置系统时间后的回调函数,回调函数的调用形式为:
- -- fnc(time,result)
- -- time表示设置之后的系统时间,table类型,例如{year=2017,month=2,day=14,hour=14,min=19,sec=23}
- -- result为true表示成功,false或者nil为失败
- -- @function[opt=nil] fun 同步结束,设置系统时间前的回调函数,回调函数的调用形式为:fun()
- -- @return nil
- --
- -- @usage
- -- 立即同步一次(仅同步这一次):
- -- ntp.timeSync()
- --
- -- 立即同步一次,之后每隔1小时自动同步一次:
- -- ntp.timeSync(1)
- --
- -- 立即同步一次(仅同步这一次),同步结束后执行fnc(time,result):
- -- ntp.timeSync(nil,fnc)
- --
- -- 立即同步一次,之后每隔24小时自动同步一次,每次同步结束后执行fnc(time,result):
- -- ntp.timeSync(24,fnc)
- function timeSync(period, fnc, fun)
- sTs,sFnc,sFun = period, fnc, fun
- sys.taskInit(ntpTime)
- end
|