微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

golang实现NTP协议获取服务器时间

// 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) <-c fmt.Println("ntp Receive ctrl-c") }

原文地址:https://www.jb51.cc/go/189534.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐