专注于高品质PHP技术等信息服务于一体 [STIEMAP] [RSS]

百度提供的广告:
python
当前位置:首页 > 技术文档 > python >  > 
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()