go ntp时间同步

go ntp时间同步


直接上代码

ntp_sync_time.go

package ntpimport ("context""fmt""math""sync""sync/atomic""time""github.com/beevik/ntp"
)/** 通过ntp方式去同步时间** CreateTime: 2023-05-19 17:31*/// ntpServers 用于ntp同步时间的服务器域名列表
var ntpServers = []string{"time.windows.com","time.tencent.com","ntp.tencent.com","0.centos.pool.ntp.org","0.rhel.pool.ntp.org","0.debian.pool.ntp.org","time.izatcloud.net","time.gpsonextra.net","0.beevik-ntp.pool.ntp.org","0.cn.pool.ntp.org","ntp.aliyun.com","time.apple.com","pool.ntp.org","0.pool.ntp.org","asia.pool.ntp.org","cn.pool.ntp.org","ntp0.ntp-servers.net","time.pool.aliyun.com","time.cloud.tencent.com","time.asia.apple.com","time.euro.apple.com","time.google.com","time.facebook.com","time.cloudflare.com","clock.sjc.he.net","clock.fmt.he.net","clock.nyc.he.net","ntp.ix.ru","ntp.jst.mfeed.ad.jp","ntp.ntsc.ac.cn","ntp1.nim.ac.cn","stdtime.gov.hk","time.hko.hk","time.smg.gov.mo","tick.stdtime.gov.tw","time.kriss.re.kr","ntp.nict.jp","s2csntp.miz.nao.ac.jp","time.nist.gov","time.nplindia.org","ntp.pagasa.dost.gov.ph","ntp1.sirim.my","ntp1.vniiftri.ru","vniiftri.khv.ru","master.ntp.mn","slave.ntp.mn","ntp.mn","ntp.atlas.ripe.net","time.ustc.edu.cn","ntp.sjtu.edu.cn","ntp.neu.edu.cn","time.jmu.edu.cn","ntp.neusoft.edu.cn","time.edu.cn","ntp.nc.u-tokyo.ac.jp","ntp.kuins.kyoto-u.ac.jp","ntp.tohoku.ac.jp",
}// ntpOffSetTime 经过ntp同步后确认的时间差值
var ntpOffSetTime time.Duration// ntp同步时间结果
var syncTimeCh = make(chan bool, 1)const (ntp_Sync_Time           = time.Hour * 3    // 每3个小时同步一次时间max_Sync_Cnt            = 10               // 最大同步协程数check_system_time       = time.Second * 30 // 检查系统时间是否发生变化间隔时间system_time_valid_range = 200              // 系统时间误差时间范围max_retry_sync_cnt      = 5                // 最多重试同步次数
)func init() {// 开协程,进行首次的同步时间操作go retrySyncNtpTime()// 开协程,定期做一次同步时间操作go loopSyncNtpTime()// 开协程,定期检查系统时间是否发生变化go loopCheckSystemTime()
}// 重试同步时间
func retrySyncNtpTime() {fmt.Println("开始同步ntp时间-------------------")var bSyncTime boolfor i := 0; i < max_retry_sync_cnt; i++ {// 同步时间操作, 同步到数据, 则直接退出if asyncNtpTime() {bSyncTime = truebreak}}// 写入同步结果select {case syncTimeCh <- bSyncTime:default:}fmt.Println("结束同步ntp时间-------------------")
}// 系统时间发生变化管道
var chSystemTimeChange = make(chan interface{}, 1)// 定期检查系统时间是否发生变化
func loopCheckSystemTime() {// 获取当前的毫秒时间lastCheckTime := time.Now().UnixMilli()// 定时器ticker := time.NewTicker(check_system_time)// 检查次数var nCheckTime int64for {<-ticker.C// 获取当前时间nowTime := time.Now().UnixMilli()// 自增检查次数nCheckTime++// 获取期望时间nExpectTime := lastCheckTime + nCheckTime*check_system_time.Milliseconds()// 检查实际时间和期望时间的差值nDiffTime := nExpectTime - nowTime// 如果误差时间大于指定的值, 则会触发更新ntp时间操作, 同时会立刻更改ntp时间差值if math.Abs(float64(nDiffTime)) >= system_time_valid_range {// engine.Log.Error("更改时间 diffTime:%d", nDiffTime)offsetTime := ntpOffSetTime.Milliseconds() + nDiffTime// 更新ntp时间差值atomic.StoreInt64((*int64)(&ntpOffSetTime), offsetTime*int64(time.Millisecond))// 更新最后检测时间及次数lastCheckTime = nowTimenCheckTime = 0// 触发同步时间操作select {case chSystemTimeChange <- struct{}{}:default:}}}
}/** loopSyncNtpTime 定时触发同步ntp时间操作*/
func loopSyncNtpTime() {// 定时器ticker := time.NewTicker(ntp_Sync_Time)defer ticker.Stop()// 通过定时器触发同步for {// 等待定时器触发select {case <-ticker.C:case <-chSystemTimeChange:// 因为系统时间触发同步操作ticker.Reset(ntp_Sync_Time)}// 同步ntp服务器时间syncNtpTime()}
}/** syncNtpTime ntp同步服务器时间** 依次遍历ntp服务器进行同步,只要同步到,就退出*/
func syncNtpTime() {// 依次遍历ntp服务器,只要有一个能获取到,就会退出for i := 0; i < len(ntpServers); i++ {ntpResp, err := ntp.Query(ntpServers[i])if err != nil {// engine.Log.Error("[%s] 无法访问了, err:%s", ntpServers[i], err)continue}// engine.Log.Info("同步到时间[%s] %d", ntpServers[i], ntpResp.ClockOffset)// 获取到ntp信息,保存时间差值atomic.StoreInt64((*int64)(&ntpOffSetTime), int64(ntpResp.ClockOffset))break}
}/** asyncNtpTime 异步进行ntp同步服务器时间** 开启10个协程, 同时去同步ntp时间, 只要有一个同步到就可以退出了*/
func asyncNtpTime() bool {getValue := false                                       // 是否获取到值标识ctx, cancel := context.WithCancel(context.Background()) // cancel的contextoffSetCh := make(chan time.Duration, 1)                 // 获取时间差值管道// 启动协程,获取时间差值内容go func() {select {case offSetTime := <-offSetCh: // 获取到结果,更新ntp服务器时间差值// engine.Log.Info("Get value!!! %s", offSetTime)atomic.StoreInt64((*int64)(&ntpOffSetTime), int64(offSetTime))getValue = true // 触发获取数据状态cancel()        // 触发context关闭case <-ctx.Done(): // 所有的请求都执行完,却没有获取到时间差值// engine.Log.Info("启动协程,获取时间差值内容 ctx.Done()!!!")}}()taskCh := make(chan string, 1) // 任务管道var wg sync.WaitGroup// 启动指定的协程,从任务管道中竞争资源,进行获取ntp时间操作for i := 0; i < max_Sync_Cnt; i++ {wg.Add(1)go func(i int, ctx context.Context) {defer wg.Done()// defer engine.Log.Error("11111 [goroutine%d] 退出!!!!\n", i)// var nIndex intfor v := range taskCh {// nIndex++// engine.Log.Info("11111 [goroutine%d] 开始处理第%d个数据", i, nIndex)var ntpResp *ntp.Response                                // ntp时间同步返回值var err error                                            // 获取错误信息ctx2, cancel2 := context.WithTimeout(ctx, time.Second*5) // 超时contextchNetReq := make(chan interface{}, 1)                    // 获取连接结果管道// 启动协程,获取请求,拿到结果后,写入连接结果管道go func() {ntpResp, err = ntp.Query(v)select {case chNetReq <- struct{}{}:default:}}()// 等待结果、超时、或运行结束标识select {case <-chNetReq: // 等到请求结果返回cancel2()if err != nil || ntpResp == nil {// engine.Log.Info("11111 [goroutine%d][%d] %s 无法访问了 %s", i, nIndex, v, err)continue}// engine.Log.Info("11111 [goroutine%d][%d] %s 获取到数据", i, nIndex, v)// 结算时间差值offSetTime := ntpResp.ClockOffset// 尝试将时间差值写入结果中select {case offSetCh <- offSetTime:// engine.Log.Info("11111 [goroutine%d][%d] %s 成功写入数据", i, nIndex, v)default:}returncase <-ctx2.Done(): // 超时,或触发结束标识// engine.Log.Info("11111 [goroutine%d][%d] %s 超时或触发结束标识", i, nIndex, v)cancel2()}}}(i, ctx)}// 依次将请求写入到任务管道中for i := 0; i < len(ntpServers); i++ {taskCh <- ntpServers[i]// engine.Log.Info("22222 写入到channel中 %d", i)if getValue {cancel()// engine.Log.Info("22222 get value!!! break for range")break}}// 关闭管道,从而使所有的协程处理完任务后,不再继续等待任务,退出执行协程close(taskCh)// 等待所有任务执行完毕wg.Wait()cancel() // 运行结束,关闭contextreturn getValue
}/** GetNtpTime 获取ntp同步之后的当前时间** @return	ntpNowTime	time.Time	同步ntp后的当前时间*/
func GetNtpTime() time.Time {// 当前时间,加上同步的时间差,就可以得到同步的时间offSetTime := atomic.LoadInt64((*int64)(&ntpOffSetTime))t := time.Now()ntpNowTime := t.Add(time.Duration(offSetTime))return ntpNowTime
}/** GetNtpOffsetTime 获取ntp的时间差值** @return	offSetTime	time.Duration	ntp时间差值*/
func GetNtpOffsetTime() time.Duration {return time.Duration(atomic.LoadInt64((*int64)(&ntpOffSetTime)))
}/** TriggerNtpSync 主动触发ntp进行时间同步, 不需要等待是否执行成功的结果*/
func TriggerNtpSync() {// 触发ntp时间同步操作go asyncNtpTime()
}/** TriggerNtpSyncWaitRes 主动触发ntp进行时间同步, 并返回触发是否成功标识** @return res		bool	是否同步成功*/
func TriggerNtpSyncWaitRes() bool {// 触发ntp时间同步操作return asyncNtpTime()
}/** WaitSyncTimeFinish 等待ntp时间同步结果** @return	res		bool	是否同步成功*/
func WaitSyncTimeFinish() bool {// 获取同步结果res := <-syncTimeCh// 写回同步结果select {case syncTimeCh <- res:default:}return res
}

测试代码

package ntpimport ("testing""time""gitee.com/prestonTao/libp2parea/engine"
)func TestNtp(t *testing.T) {time.Sleep(time.Second * 5)t1 := time.Now()ntpt := GetNtpTime()t2 := time.Now()engine.Log.Info(ntpt.String())engine.Log.Info(t1.String())engine.Log.Info(t2.String())engine.Log.Info(GetNtpOffsetTime().String())for i := 0; i < 10; i++ {time.Sleep(time.Second * 30)t := GetNtpTime()engine.Log.Info(t.String())engine.Log.Info(GetNtpOffsetTime().String())engine.Log.Info("----------------")}
}func TestNtpSync(t *testing.T) {time.Sleep(time.Second * 5)t1 := time.Now()ntpt := GetNtpTime()t2 := time.Now()engine.Log.Info(ntpt.String())engine.Log.Info(t1.String())engine.Log.Info(t2.String())engine.Log.Info(GetNtpOffsetTime().String())for i := 0; i < 10; i++ {time.Sleep(time.Second * 30)// TriggerNtpSync()TriggerNtpSyncWaitRes()t := GetNtpTime()engine.Log.Info(t.String())engine.Log.Info(GetNtpOffsetTime().String())engine.Log.Info("----------------")}
}func TestNtpSystemTimeChange(t *testing.T) {// 测试修改系统时间, ntp的同步机制是否正常time.Sleep(time.Second * 5)engine.Log.Info("Ntp 差值:%s", GetNtpOffsetTime().String())for {time.Sleep(time.Second * 5)engine.Log.Info("----------------")engine.Log.Info("Ntp 时间:%s", GetNtpTime().String())engine.Log.Info("Ntp 差值:%s", GetNtpOffsetTime().String())engine.Log.Info("----------------")}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/141621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么叫做云安全?云安全有哪些要求?

云安全(Cloud Security)是一种基于云计算的安全防护策略&#xff0c;旨在保护企业数据和应用程序的安全性和完整性。云安全利用云计算的分布式处理和存储能力&#xff0c;以更高效、更灵活的方式提供安全服务。 云安全的要求主要包括以下几个方面&#xff1a; 数据安全和隐私保…

智能化的同城服务共享台球室小程序系统,提升台球室运营效率

一、引言 在当今数字化时代&#xff0c;智能化技术正在改变各行各业的运营模式。台球室作为传统的休闲娱乐场所&#xff0c;也需要与时俱进&#xff0c;借助智能化技术提升运营效率。本文将探讨如何通过智能化的同城服务共享台球室小程序系统&#xff0c;提升台球室的运营效率…

消息中间件,RabbitMQ,kafka常见面试题

消息中间件&#xff0c;RabbitMQ&#xff0c;kafka常见面试题 文章目录 消息中间件&#xff0c;RabbitMQ&#xff0c;kafka常见面试题RabbitMQ&#xff0c;kafkaRabbitMQ 和 Kafka 的相同点有以下几个&#xff1a; 消息中间件面试题-参考回答 RabbitMQ&#xff0c;kafka Rabbi…

Python | 机器学习之数据清洗

​ &#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《人工智能奇遇记》&#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 目录结构 1. 机器学习之数据清洗概念 1.1 机器学习 1.2 数据清洗 2. 数据清洗 2.1 实验目的…

Apache Airflow (六) :DAG catchup 参数设置

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

从0到0.01入门React | 010.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

ARM 作业

src/uart.c #include"uart.h"void uart4_init() {//设置UART4的RCc时钟使能//RCC_MP_APB1ENSETR[16]->1RCC->MP_APB1ENSETR | (0x1<<16);//设置GPIOB和GPIOG的时钟使能//RCC_MP_AHB4ENSETR[6]->1//RCC_MP_AHB4ENSETR[1]->1RCC->MP_AHB4ENSETR …

【C/PTA——8.数组2(课外实践)】

C/PTA——8.数组2&#xff08;课外实践&#xff09; 7-4 矩阵运算7-2 方阵循环右移7-3 螺旋方阵7-4 数组-杨辉三角7-5 数组-对角线求和7-6 数组-矩阵最小值 7-4 矩阵运算 #include<stdio.h> int main() {int n, i, j;int a[10][10] { 0 };scanf("%d", &n)…

电脑技巧:推荐基于浏览器的远程桌面访问控制工具

一、软件简介 Getscreen.me是一个基于浏览器的远程桌面访问控制工具&#xff0c;可以轻松地远程访问控制特定设备。并且注册登录账户实现允许设置具有永久访问权限的设备&#xff0c;可以通过一键进行快速连接访问&#xff0c;无需共享 ID、密码或任何内容。 Getscreen.me采用…

Linux可以投屏到电视吗?用网页浏览器就能投屏到电视!

Linux系统的电脑如果要投屏到安卓电视屏幕上&#xff0c;可以使用投屏工具AirDroid Cast的网页版和TV版一起实现。 首先&#xff0c;在Linux系统的电脑里用chrome浏览器或edge浏览器打开webcast.airdroid.com。这就是AirDroid Cast的网页版。你可以看到中间白色框框的右上角有个…

Flink 支持三种时间语义

在 Apache Flink 中&#xff0c;时间在流处理中是一个重要的概念&#xff0c;而时间语义则用于定义事件发生的时间。Flink 支持三种时间语义&#xff0c;分别是&#xff1a; Processing Time&#xff08;处理时间&#xff09;&#xff1a; 以机器的系统时间为基准&#xff0c;…

ARPG----C++学习记录04 Section8 角色类,移动

角色类输入 新建一个角色C&#xff0c;继承建立蓝图,和Pawn一样&#xff0c;绑定输入移动和相机. 在构造函数中添加这段代码也能实现。打开UsePawnControlRotation就可以让人物不跟随鼠标旋转 得到旋转后的向前向量 使用旋转矩阵 想要前进方向和旋转的方向对应。获取当前控制…

常用的原型设计工具集合

文章目录 前言Axure RPMockplusSketchFigmaPixso 前言 软件产品的诞生注定要经历一个过程&#xff1a;需求分析、设计、开发、测试和在线。在设计阶段&#xff0c;原型设计是软件设计和开发的重要保证。与其他工作一样&#xff0c;高效的原型设计需要相应工具的协助才能完成原…

2.3 Windows驱动开发:内核字符串转换方法

在内核编程中字符串有两种格式ANSI_STRING与UNICODE_STRING&#xff0c;这两种格式是微软推出的安全版本的字符串结构体&#xff0c;也是微软推荐使用的格式&#xff0c;通常情况下ANSI_STRING代表的类型是char *也就是ANSI多字节模式的字符串&#xff0c;而UNICODE_STRING则代…

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法

文章目录 0 代码仓库1 Dijkstra算法2 Dijkstra算法的实现2.1 设置距离数组2.2 找到当前路径的最小值 curdis&#xff0c;及对应的该顶点cur2.3 更新权重2.4 其他接口2.4.1 判断某个顶点的连通性2.4.2 求源点s到某个顶点的最短路径 3使用优先队列优化-Dijkstra算法3.1 设计内部类…

Vue 小黑记事本组件板

渲染功能&#xff1a; 1.提供数据&#xff1a; 提供在公共的父组件 App.vue 2.通过父传子&#xff0c;将数据传递给TodoMain 3.利用 v-for渲染 添加功能&#xff1a; 1.收集表单数据 v-model 2.监听事件&#xff08;回车点击都要添加&#xff09; 3.子传父&#xff0c;讲…

Redis解决缓存问题

目录 一、引言二、缓存三、Redis缓存四、缓存一致性1.缓存更新策略2.主动更新 五、缓存穿透六、缓存雪崩七、缓存击穿1.基于互斥锁解决具体业务2.基于逻辑过期解决具体业务 一、引言 在一些大型的网站中会有十分庞大的用户访问流量&#xff0c;而过多的用户访问对我们的MySQL数…

原生JS实现视频截图

视频截图效果预览 利用Canvas进行截图 要用原生js实现视频截图&#xff0c;可以利用canvas的绘图功能 ctx.drawImage&#xff0c;只需要获取到视频标签&#xff0c;就可以通过drawImage把视频当前帧图像绘制在canvas画布上。 const video document.querySelector(video) con…

Nginx 使用笔记大全(唯一入口)

Linux服务器因为Nginx日志access.log文件过大项目无法访问 项目处于运行状态下无法访问&#xff0c;第一步查看磁盘状态 1、查看磁盘状态 df -h 2、查找100M以上的文件 find / -size 100M |xargs ls -lh 3、删除文件 rm -rf /usr/local/nginx/logs/access.log 4、配置nginx.…

ubuntu使用xdebug测试php的性能

sudo mkdir /var/log/xdebug/ sudo mkdir /var/log/xdebug/ciunit mkdir /var/log/xdebug/wp_number1g.com sudo chmod -R 777 /var/log/xdebug/ pecl install xdebug vim /etc/php5/conf.d/xdebug.ini 写入 extensionxdebug.so xdebug.extended_info0 sudo apt-get inst…