// 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")
}
有疑问加站长微信联系(非本文作者)