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") }

相关文章

什么是Go的接口? 接口可以说是一种类型,可以粗略的理解为他...
1、Golang指针 在介绍Golang指针隐式间接引用前,先简单说下...
1、概述 1.1&#160;Protocol buffers定义 Protocol buffe...
判断文件是否存在,需要用到"os"包中的两个函数: os.Stat(...
1、编译环境 OS :Loongnix-Server Linux release 8.3 CPU指...
1、概述 Golang是一种强类型语言,虽然在代码中经常看到i:=1...