python 实现 ntp 网络对时详解
ntp 网络时间 rfc 1035 使用 dup 123 端口发送接收报文。 特别说明的地方是,ntp 的时间是基于1900年过去的秒数,而普通程序都 是1970年开始计数。 ntp 时间格式是 64bit 长度,高32bit 放时间秒数 低32bit 放的是毫秒。 原理就是,客户端向ntp服务器发送同步报文。 服务器返回报文,比较本地时间和服务器时间的差别计算出offset #coding:utf-8 from __future__ import division import socket import struct import time ntp_server = 'time.windows.com' ntp_port = 123 #创建一个ipv4 的 udp 连接 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) """ LI 3 未同步状态 2bit VN 3 ntp 版本3 3bit Mode 3 client 客户端模式 3bit Stratum 1 系统时钟层数取1 8bit Poll 10 两个报文相隔 8bit Precision 1 系统精度 8bit Root Delay 默认0 32bit Root Dispersion 默认0 32bit Reference Identifier 默认0 32bit Reference Timestamp 默认0 64bit Originate Timestamp 默认0 64bit Receive Timestamp 默认0 64bit Transmit Timestamp 当前系统时间 64bit 0x83aa7e80 是1970 到 1900年的秒数 Transmit Timestamp 高32位存秒数 低32位存毫秒 这里什么发0 也没可以用 ,程序自己记录下来就行 """ time1990_1970 = 0x83aa7e80 #包离开的时间 t1 = time.time() #使用struct pack 打包数据8bit 用 B 一个字节宽度 I 32bit Q 64bit ntppack = struct.pack("!BBBBIIIQQQQ",3<<6 | 3<<3 | 3,1,10,1,1,10,0,0,0,0,0) sock.sendto(ntppack, (ntp_server,ntp_port)) resp,addr = sock.recvfrom(512) #包到达的时间 t4 = time.time() #解包 这里LI VN Mode Stratum 等放到了一个64bit 的里面,所有格式和上面的打包不同 (vi,root,refeTime,oriTime,receTime,tranTime) = struct.unpack("!QQQQQQ",resp) #Mode 是 4 是服务器返回标志 if vi == vi | 4<<56 : #64bit 1900年时间转普通时间 receTime = (receTime/(2**32) - time1990_1970) tranTime = (tranTime/(2**32) - time1990_1970) t4 +=((receTime - t1) + (tranTime - t4)) /2 print time.strftime("ntp server date: %Y-%m-%d %H:%M:%S", time.localtime(t4)) sock.close()