Nyob zoo, cov neeg siv Habrahabr. Hnub no kuv xav tham txog kev sau koj tus kheej NTP client yooj yim. Peb yuav feem ntau tham txog cov qauv pob ntawv thiab yuav ua li cas ua cov lus teb los ntawm NTP server. Cov lej yuav raug sau ua Python, vim kuv ntseeg tias tsis muaj lus zoo dua rau hom no. Cov neeg paub txog qhov kev kawm yuav pom qhov zoo sib xws rau ntplib - Kuv tau tshoov siab los ntawm nws.
Yog li, NTP yog dab tsi? NTP yog ib qho protocol rau kev sib cuam tshuam nrog cov servers sijhawm tseeb. Cov protocol no siv rau hauv ntau lub tshuab niaj hnub. Piv txwv li, qhov kev pabcuam w32tm hauv qhov rais.
Muaj tag nrho 5 hom ntawm NTP protocol. Thawj hom, version 0 (1985, RFC958), tam sim no suav tias tsis siv lawm. Cov version tshiab dua tam sim no siv: version 1 (1988, RFC1059), version 2 (1989, RFC1119), version 3 (1992, RFC1305), thiab version 4 (1996, RFC2030). Version 1-4 sib xws; lawv tsuas yog txawv hauv lawv cov algorithms ua haujlwm. servers.
Hom ntawv pob khoom

Qhov taw qhia dhia (qhov qhia txog kev kho) - tus lej qhia txog qhov ceeb toom thib ob. Lub ntsiab lus:
- 0 - tsis muaj kev kho
- 1 - feeb kawg ntawm hnub muaj 61 vib nas this
- 2 - feeb kawg ntawm hnub muaj 59 vib nas this
- 3 - lub server ua haujlwm tsis zoo (lub sijhawm tsis sib dhos)
Tus lej xov tooj (tus lej version) - NTP protocol version tus lej (1-4).
hom (hom) - hom kev ua haujlwm ntawm tus xa pob ntawv. Cov nqi ntawm 0 txog 7, feem ntau yog:
- 3 – tus neeg siv khoom
- 4 - tus neeg rau zaub mov
- 5 - hom kev tshaj tawm
stratum (theem txheej) - tus naj npawb ntawm cov txheej nruab nrab ntawm lub server thiab lub moos siv (1 - lub server siv cov ntaub ntawv ncaj qha los ntawm lub moos siv, 2 - lub server siv cov ntaub ntawv los ntawm lub server ntawm theem 1, thiab lwm yam).
pas dej ua ke — ib tus lej kos npe uas sawv cev rau lub sijhawm siab tshaj plaws ntawm cov lus sib law liag. Tus neeg siv khoom NTP qhia ntawm no lub sijhawm uas nws xav tias yuav xaiv lub server, thiab NTP server qhia lub sijhawm uas nws xav tias yuav raug xaiv. Tus nqi yog sib npaug rau binary logarithm ntawm vib nas this.
Precision (precision) — ib qho integer kos npe uas sawv cev rau qhov tseeb ntawm lub moos system. Tus nqi yog sib npaug rau binary logarithm ntawm qhov thib ob.
Kev ncua hauv paus (server latency) - lub sijhawm uas nws siv rau lub moos nyeem kom mus txog NTP server, ua tus lej ntawm cov vib nas this ruaj khov.
Kev tawg ntawm cov hauv paus hniav (kev sib kis ntawm lub moos server) — NTP server lub moos kis raws li tus lej ntawm cov vib nas this ruaj khov.
Tus lej siv rau kev siv (qhov chaw cim qhia) - lub moos ID. Yog tias lub server muaj stratum 1, ces tus lej ID yog lub npe ntawm lub moos atomic (4 tus cim ASCII). Yog tias lub server siv lwm lub server, ces tus lej ID muaj qhov chaw nyob ntawm lub server ntawd.
4 daim teb kawg sawv cev rau lub sijhawm - 32 bits - qhov integer, 32 bits - qhov fractional.
reference — cov ntawv nyeem moos tshiab kawg ntawm lub server.
Keeb kwm - lub sijhawm uas lub pob ntawv raug xa mus (sau los ntawm lub server - ntxiv rau qhov ntawd hauv qab no).
Tau txais - lub sijhawm ntawm lub server tau txais pob ntawv.
Kis - lub sijhawm uas pob ntawv raug xa los ntawm lub server mus rau tus neeg siv khoom (tus neeg siv khoom sau tiav, ntxiv rau qhov ntawd hauv qab no).
Peb yuav tsis xav txog ob lub teb kawg.
Cia peb sau peb pob khoom:
Tus lej pob khoom
class NTPPacket:
_FORMAT = "!B B b b 11I"
def __init__(self, version_number=2, mode=3, transmit=0):
# Necessary of enter leap second (2 bits)
self.leap_indicator = 0
# Version of protocol (3 bits)
self.version_number = version_number
# Mode of sender (3 bits)
self.mode = mode
# The level of "layering" reading time (1 byte)
self.stratum = 0
# Interval between requests (1 byte)
self.pool = 0
# Precision (log2) (1 byte)
self.precision = 0
# Interval for the clock reach NTP server (4 bytes)
self.root_delay = 0
# Scatter the clock NTP-server (4 bytes)
self.root_dispersion = 0
# Indicator of clocks (4 bytes)
self.ref_id = 0
# Last update time on server (8 bytes)
self.reference = 0
# Time of sending packet from local machine (8 bytes)
self.originate = 0
# Time of receipt on server (8 bytes)
self.receive = 0
# Time of sending answer from server (8 bytes)
self.transmit = transmit
Yuav kom xa (thiab tau txais) ib pob ntawv mus rau lub server, peb yuav tsum muaj peev xwm hloov nws mus rau hauv ib qho array ntawm bytes.
Rau qhov kev ua haujlwm no (thiab rov qab), peb yuav sau ob lub luag haujlwm - pack() thiab unpack():
Lub luag haujlwm ntawm pob khoom
def pack(self):
return struct.pack(NTPPacket._FORMAT,
(self.leap_indicator << 6) +
(self.version_number << 3) + self.mode,
self.stratum,
self.pool,
self.precision,
int(self.root_delay) + get_fraction(self.root_delay, 16),
int(self.root_dispersion) +
get_fraction(self.root_dispersion, 16),
self.ref_id,
int(self.reference),
get_fraction(self.reference, 32),
int(self.originate),
get_fraction(self.originate, 32),
int(self.receive),
get_fraction(self.receive, 32),
int(self.transmit),
get_fraction(self.transmit, 32))
Lub luag haujlwm ntawm unpacking
def unpack(self, data: bytes):
unpacked_data = struct.unpack(NTPPacket._FORMAT, data)
self.leap_indicator = unpacked_data[0] >> 6 # 2 bits
self.version_number = unpacked_data[0] >> 3 & 0b111 # 3 bits
self.mode = unpacked_data[0] & 0b111 # 3 bits
self.stratum = unpacked_data[1] # 1 byte
self.pool = unpacked_data[2] # 1 byte
self.precision = unpacked_data[3] # 1 byte
# 2 bytes | 2 bytes
self.root_delay = (unpacked_data[4] >> 16) +
(unpacked_data[4] & 0xFFFF) / 2 ** 16
# 2 bytes | 2 bytes
self.root_dispersion = (unpacked_data[5] >> 16) +
(unpacked_data[5] & 0xFFFF) / 2 ** 16
# 4 bytes
self.ref_id = str((unpacked_data[6] >> 24) & 0xFF) + " " +
str((unpacked_data[6] >> 16) & 0xFF) + " " +
str((unpacked_data[6] >> 8) & 0xFF) + " " +
str(unpacked_data[6] & 0xFF)
self.reference = unpacked_data[7] + unpacked_data[8] / 2 ** 32 # 8 bytes
self.originate = unpacked_data[9] + unpacked_data[10] / 2 ** 32 # 8 bytes
self.receive = unpacked_data[11] + unpacked_data[12] / 2 ** 32 # 8 bytes
self.transmit = unpacked_data[13] + unpacked_data[14] / 2 ** 32 # 8 bytes
return self
Rau cov neeg tub nkeeg, ntawm no yog ib qho ntxiv ntawm cov lej uas hloov ib pob ntawv mus rau hauv ib txoj hlua zoo nkauj.
def to_display(self):
return "Leap indicator: {0.leap_indicator}n"
"Version number: {0.version_number}n"
"Mode: {0.mode}n"
"Stratum: {0.stratum}n"
"Pool: {0.pool}n"
"Precision: {0.precision}n"
"Root delay: {0.root_delay}n"
"Root dispersion: {0.root_dispersion}n"
"Ref id: {0.ref_id}n"
"Reference: {0.reference}n"
"Originate: {0.originate}n"
"Receive: {0.receive}n"
"Transmit: {0.transmit}"
.format(self)
Xa ib pob ntawv mus rau lub server
Yuav tsum xa ib pob ntawv uas muaj cov teb uas tau sau tiav mus rau lub server. version, hom и Kis. Cov Kis Koj yuav tsum teev lub sijhawm tam sim no ntawm lub tshuab hauv zos (tus lej ntawm vib nas this txij li Lub Ib Hlis 1, 1900), version - ib qho ntawm 1-4, hom - 3 (hom neeg siv khoom).
Tus neeg rau zaub mov, tom qab tau txais qhov kev thov, sau tag nrho cov teb hauv pob ntawv NTP, theej lawv rau hauv daim teb Keeb kwm lub ntsiab lus los ntawm Kis, uas tuaj hauv daim ntawv thov. Nws yog ib qho paub tsis meej rau kuv vim li cas tus neeg siv khoom tsis tuaj yeem sau lawv lub sijhawm tam sim ntawd hauv daim teb. Keeb kwmYog li ntawd, thaum lub pob ntawv rov qab los, tus neeg siv khoom muaj 4 lub sijhawm tus nqi - lub sijhawm uas qhov kev thov tau xa mus (Keeb kwm), lub sijhawm uas tus neeg rau zaub mov tau txais qhov kev thov (Tau txais), lub sijhawm uas lub server siv los xa cov lus teb (Kis) thiab lub sijhawm uas tus neeg siv khoom siv los txais cov lus teb - Tuaj txog (tsis nyob hauv pob khoom). Siv cov nqi no, peb tuaj yeem teem sijhawm kom raug.
Code rau kev xa thiab txais pob ntawv
# Time difference between 1970 and 1900, seconds
FORMAT_DIFF = (datetime.date(1970, 1, 1) - datetime.date(1900, 1, 1)).days * 24 * 3600
# Waiting time for recv (seconds)
WAITING_TIME = 5
server = "pool.ntp.org"
port = 123
packet = NTPPacket(version_number=2, mode=3, transmit=time.time() + FORMAT_DIFF)
answer = NTPPacket()
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.settimeout(WAITING_TIME)
s.sendto(packet.pack(), (server, port))
data = s.recv(48)
arrive_time = time.time() + FORMAT_DIFF
answer.unpack(data)
Kev ua cov ntaub ntawv los ntawm lub server
Kev ua cov ntaub ntawv los ntawm lub server zoo ib yam li cov kev ua ntawm tus txiv neej Askiv hauv qhov teeb meem qub los ntawm Raymond M. Smullyan (1978): "Ib tug txiv neej tsis muaj lub moos dab teg, tab sis nws muaj lub moos phab ntsa raug hauv tsev, uas qee zaum nws tsis nco qab tig. Muaj ib hnub, tom qab tsis nco qab tig nws lub moos, nws mus ntsib ib tug phooj ywg, siv hmo ntuj nrog nws, thiab, thaum rov qab los tsev, tswj hwm teeb tsa lub moos kom raug. Nws tswj hwm qhov no li cas yog tias lub sijhawm mus ncig tsis paub ua ntej?" Cov lus teb yog: "Thaum tawm hauv tsev, tus txiv neej yuav tig nws lub moos thiab nco qab qhov chaw ntawm tes. Thaum tuaj txog ntawm nws tus phooj ywg lub tsev thiab tawm hauv pawg neeg, nws sau lub sijhawm uas nws tuaj txog thiab tawm mus. Qhov no tso cai rau nws nrhiav seb nws siv sijhawm ntev npaum li cas ntawm pawg neeg. Thaum rov qab los tsev thiab saib nws lub moos, tus txiv neej txiav txim siab lub sijhawm uas nws tsis tuaj. Los ntawm kev rho tawm lub sijhawm uas nws siv ntawm pawg neeg ntawm lub sijhawm no, tus txiv neej yuav pom lub sijhawm siv rau kev mus ncig. Los ntawm kev ntxiv ib nrab ntawm lub sijhawm siv ntawm txoj kev rau lub sijhawm uas nws tawm hauv pawg neeg, nws muaj lub sijhawm los nrhiav lub sijhawm uas nws tuaj txog tsev thiab kho tes ntawm nws lub moos raws li qhov tsim nyog."
Peb pom lub sijhawm uas tus neeg rau zaub mov siv los ua qhov kev thov:
- Peb pom lub sijhawm mus ncig ntawm lub pob ntawv los ntawm tus neeg siv khoom mus rau lub server: ((Tuaj txog - Pib) - (Xa mus - Tau txais)) / 2
- Peb pom qhov sib txawv ntawm lub sijhawm ntawm tus neeg siv khoom thiab lub sijhawm ntawm lub server:
Txais - Pib - ((Tuaj txog - Pib) - (Xa - Txais)) / 2 =
2 * Txais - 2 * Pib - Tuaj txog + Pib + Xa - Txais =
Txais - Pib - Tuaj txog + Xa
Peb ntxiv cov txiaj ntsig uas tshwm sim rau lub sijhawm hauv zos thiab txaus siab rau lub neej.
Cov zis ntawm qhov tshwm sim
time_different = answer.get_time_different(arrive_time)
result = "Time difference: {}nServer time: {}n{}".format(
time_different,
datetime.datetime.fromtimestamp(time.time() + time_different).strftime("%c"),
answer.to_display())
print(result)
Pab tau .
Tau qhov twg los: www.hab.com
