前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ntp服务器udp协议,golang实现NTP协议获取服务器时间[通俗易懂]

ntp服务器udp协议,golang实现NTP协议获取服务器时间[通俗易懂]

作者头像
全栈程序员站长
发布2022-09-27 15:35:07
3.8K0
发布2022-09-27 15:35:07
举报
文章被收录于专栏:全栈程序员必看

// file project main.go

package main

import (

“encoding/binary”

“fmt”

“net”

“os”

“os/signal”

“sync”

“time”

)

const (

NTP_SERVER_IP = “time.windows.com” /*NTP IP*/

NTP_PORT_STR = “123” /*NTP专用端口号字 符串*/

NTP_PCK_LEN = 48

LI = 0

VN = 3

MODE = 3

STRATUM = 0

POLL = 4

PREC = -6

JAN_1970 = 0x83aa7e80 /* 1900年~1970年之间的时间秒数 */

)

func NTPFRAC(x int64) int64 {

return (4294*(x) + ((1981 * (x)) >> 11))

}

func USEC(x int64) int64 {

return (((x) >> 12) – 759*((((x)>>10)+32768)>>16))

}

type ntp_time struct {

coarse uint32

fine uint32

}

type ntp_packet struct {

leap_ver_mode byte

startum byte

poll byte

precision byte

root_delay int

root_dispersion int

reference_identifier int

reference_timestamp ntp_time

originage_timestamp ntp_time

receive_timestamp ntp_time

transmit_timestamp ntp_time

}

var protocol []byte

func construct_packet() ([]byte, int) {

reqData := make([]byte, NTP_PCK_LEN)

//设置16字节的包头

head := (LI << 30) | (VN << 27) | (MODE << 24) | (STRATUM << 16) | (POLL << 8) | (PREC & 0xff)

binary.BigEndian.PutUint32(reqData[0:4], uint32(head))

//设置Root Delay、Root Dispersion和Reference Indentifier

binary.BigEndian.PutUint32(reqData[4:8], uint32(1<<16))

binary.BigEndian.PutUint32(reqData[8:12], uint32(1<<16))

binary.BigEndian.PutUint32(reqData[12:16], uint32(1<<16))

//设置Timestamp部分

timeOri := JAN_1970 + time.Now().Unix()

//设置Transmit Timestamp coarse

binary.BigEndian.PutUint32(reqData[40:44], uint32(timeOri))

//设置Transmit Timestamp fine

binary.BigEndian.PutUint32(reqData[44:48], uint32(NTPFRAC(timeOri)))

return reqData, NTP_PCK_LEN

}

func main() {

protocol = make([]byte, 32)

// Resolve address

fmt.Println(“ntp begin NTC…..”)

udpAddr, errData := net.ResolveUDPAddr(“udp”, NTP_SERVER_IP+”:”+NTP_PORT_STR)

if nil != errData {

fmt.Printf(“ntp connect err: %v\n”, errData)

return

}

fmt.Println(“ntp after ResolveTCPAddr…..: “, udpAddr)

conn, err := net.DialUDP(“udp”, nil, udpAddr)

if nil != err {

fmt.Printf(“ntp net connect error: %v\n”, err)

return

}

fmt.Println(“ntp after DialUDP…..”)

data, packet_len := construct_packet()

if packet_len == 0 {

fmt.Println(“ntp packet len is 0”)

return

}

fmt.Println(“ntp begin send: %v, data: %v”, packet_len, data)

conn.SetWriteDeadline(time.Now().Add(time.Second))

size, err := conn.Write(data)

if nil != err {

fmt.Printf(“ntp write data error: %v\n”, err)

return

} else {

fmt.Printf(“ntp write len: %v\n”, size)

}

fmt.Println(“after send”)

recvBody := make([]byte, 4096)

wait := &sync.WaitGroup{}

wait.Add(1)

go func() {

defer wait.Done()

for {

fmt.Println(“ntp begin read”)

conn.SetReadDeadline(time.Now().Add(time.Second))

size, remoteAddr, err := conn.ReadFromUDP(recvBody)

if nil != err {

fmt.Printf(“ntp read data error: %v\n”, err)

} else {

fmt.Printf(“ntp read len: %v\n”, size)

}

fmt.Println(“ntp after read, remoteAddr: %v\n”, remoteAddr.String(), recvBody[:size])

break

}

}()

wait.Wait()

var dataStru ntp_packet

dataStru.transmit_timestamp.coarse = binary.BigEndian.Uint32(recvBody[40:44]) – JAN_1970

dataStru.transmit_timestamp.fine = uint32(USEC(int64(binary.BigEndian.Uint32(recvBody[44:48]))))

fmt.Println(dataStru)

//等待退出

c := make(chan os.Signal, 1)

signal.Notify(c, os.Interrupt, os.Kill)

fmt.Println(“ntp Receive ctrl-c”)

}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/183733.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档