Ukubhala umxhasi we-NTP olula

Molweni habrausers. Namhlanje ndifuna ukuthetha malunga nendlela yokubhala umxhasi wakho we-NTP olula. Ngokwenene, incoko iya kujika kwisakhiwo sepakethi kunye nendlela impendulo evela kumncedisi we-NTP iqhutywe ngayo. Ikhowudi iya kubhalwa kwi-python, kuba, ngokombono wam, akukho lulwimi olungcono kwizinto ezinjalo. I-Connoisseurs iya kuqwalasela ukufana kwekhowudi kunye nekhowudi ye-ntplib - "ndiphefumlelwe" ngayo.

Ngoko ke yintoni i-NTP? I-NTP yiprothokholi yokunxibelelana nabancedisi bexesha. Le protocol isetyenziswa koomatshini abaninzi bale mihla. Umzekelo, inkonzo ye-w32tm kwiifestile.

Kukho iinguqulelo ezi-5 zeprotocol ye-NTP iyonke. Eyokuqala, inguqulelo 0 (1985, RFC958) ijongwa njengephelelwe lixesha. Ezintsha ngoku zisetyenziswayo, eyoku-1 (ngo-1988, i-RFC1059), eyesi-2 (ngo-1989, i-RFC1119), eyesi-3 (ngo-1992, i-RFC1305) neyesi-4 (ngo-1996, i-RFC2030). Iinguqulelo ze-1-4 zihambelana nomnye, zihluke kuphela kwii-algorithms zeeseva.

I-Packet Format

Ukubhala umxhasi we-NTP olula

Isalathisi sokutsiba (isalathisi sokulungisa) linani elibonisa isilumkiso sesibini sokutsiba. Intsingiselo:

  • 0 - akukho lungiso
  • I-1 - umzuzu wokugqibela wosuku uqulethe imizuzwana engama-61
  • I-2 - umzuzu wokugqibela wosuku uqulethe imizuzwana ye-59
  • I-3-ukusilela kweseva (ixesha liphumile kwi-sync)

Inombolo yenguqulo (inombolo yoguqulelo) - Inombolo yenguqulo ye-NTP yeprotocol (1-4).

ifashoni (imo) β€” imo yokusebenza yomthumeli wepakethi. Ixabiso ukusuka ku-0 ukuya ku-7, ixhaphake kakhulu:

  • 3 - umxhasi
  • 4 - umncedisi
  • I-5 - imo yokusasaza

Umgaqo (inqanaba lomgangatho) - inani leengqimba eziphakathi phakathi komncedisi kunye newashi yereferensi (1 - umncedisi uthatha idatha ngokuthe ngqo kwiwashi yereferensi, i-2 - umncedisi uthatha idatha kumncedisi kunye nenqanaba 1, njl.).
ichibi yinani elipheleleyo esayiniweyo elimele elona thuba liphezulu phakathi kwemiyalezo elandelelanayo. Umxhasi we-NTP ukhankanya apha isithuba elindele ukuvotelwa ngaso umncedisi, kwaye umncedisi we NTP ukhankanya isithuba elindele ukuvotelwa ngaso. Ixabiso lilingana nelogarithm yokubini yemizuzwana.
hle (ukuchaneka) yinani elipheleleyo esayiniweyo elimele ukuchaneka kwewotshi yesixokelelwano. Ixabiso lilingana nelogarithm yokubini yemizuzwana.
ukulibaziseka kweengcambu (umncedisi we-latency) lixesha elithathayo ukuba iwotshi ifike kwiseva ye-NTP, njengenani lendawo esisigxina yemizuzwana.
ukusasazwa kweengcambu (Ukusasazwa komncedisi) - Ukusasazwa kwewotshi yeseva ye-NTP njengenani lendawo esisigxina yemizuzwana.
Ref id (i-id yomthombo) - i-id yokujonga. Ukuba umncedisi unestratum 1, ke ref id ligama lekloko yeathom (abalinganiswa aba-4 ASCII). Ukuba umncedisi usebenzisa enye iseva, ngoko i-id yeref iqulethe idilesi yalo mncedisi.
Iindawo ezi-4 zokugqibela lixesha - amasuntswana angama-32 - inani elipheleleyo, amasuntswana angama-32 - inxalenye yeqhezu.
isingqiniso - iwotshi yamva nje kumncedisi.
Imvelaphi - ixesha apho ipakethi ithunyelwe (izaliswe ngumncedisi - ngakumbi kule ngezantsi).
Fumana – ixesha apho ipakethi yamkelwa ngumncedisi.
hambisa - ixesha apho ipakethe ithunyelwe kwi-server ukuya kumxhasi (ezaliswe ngumxhasi, ngakumbi kule ngezantsi).

Imimandla emibini yokugqibela ayiyi kuqwalaselwa.

Masibhale ipakethe yethu:

Ikhowudi yephakheji

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

Ukuthumela (kwaye nokufumana) ipakethi kumncedisi, kufuneka sikwazi ukuyijika ibe luluhlu lwee-bytes.
Kule (kunye nokubuyisela umva) ukusebenza, siya kubhala imisebenzi emibini - pack() kwaye unpack():

umsebenzi wokupakisha

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

umsebenzi wokukhulula

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

Kubantu abanobuvila, njengesicelo - ikhowudi ejika ipakethe ibe ngumtya omhle

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)

Ukuthumela ipakethe kumncedisi

Thumela ipakethi enemihlaba ezaliswe kumncedisi inguqulelo, ifashoni ΠΈ hambisa. Ku hambisa kufuneka ucacise ixesha langoku kumatshini wendawo (inani lemizuzwana ukususela ngoJanuwari 1, 1900), inguqulo - nayiphi na i-1-4, imo - 3 (imo yomthengi).

Umncedisi, xa efumene isicelo, ugcwalisa onke amasimi kwipakethi ye-NTP, ekhuphela endle Imvelaphi ixabiso ukusuka hambisa, eyafika ngesicelo. Kuyimfihlakalo kum ukuba kutheni umxhasi akakwazi ukuzalisa ngokukhawuleza ixabiso lexesha lakhe entsimini Imvelaphi. Ngenxa yoko, xa ipakethe ibuya, umxhasi unamaxabiso exesha eli-4- ixesha lokuthunyelwa kwesicelo (Imvelaphi), ixesha umncedisi afumene isicelo (Fumana), ixesha umncedisi athumele impendulo (hambisa) kunye nexesha lokufunyanwa kwempendulo ngumxhasi - Fika (hayi kwiphakheji). Ngala maxabiso sinokuseta ixesha elichanekileyo.

Ipakethi yokuthumela nokufumana ikhowudi

# 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)

Ukulungiswa kwedatha kumncedisi

Ukucutshungulwa kwedatha evela kumncedisi kuyafana nezenzo zendoda eliNgesi kwingxaki endala kaRaymond M. Smallian (1978): β€œOmnye umntu wayengenayo iwotshi yesihlahla, kodwa kukho iwotshi echanekileyo eludongeni ekhaya, awayeyifumene. ngamanye amaxesha ndilibale ngumoya. Ngenye imini, elibale ukuqala iwashi kwakhona, waya kutyelela umhlobo wakhe, wachitha ubusuku kunye naye, kwaye xa ebuyela ekhaya, wakwazi ukuseta iwotshi ngokuchanekileyo. Wakwazi njani ukwenza oku ukuba ixesha lokuhamba lalingaziwa kwangaphambili? Impendulo ithi: β€œXa umntu ephuma endlwini, uvula iwotshi aze akhumbule ukuma kwezandla. Ukuza kumhlobo kunye nokushiya iindwendwe, uqaphela ixesha lokufika nokuhamba kwakhe. Oku kumvumela ukuba afumanise ukuba wayengekho ixesha elingakanani. Xa ebuyela ekhaya aze ajonge ewotshini, umntu uyaligqiba ixesha lokungabikho kwakhe. Ukuthabatha kweli xesha ixesha alichithe etyelele, umntu ufumana ixesha elichithwe endleleni eya apho nasemva. Ngokongeza isiqingatha sexesha elichithwe endleleni kwixesha lokushiya iindwendwe, ufumana ithuba lokufumanisa ixesha lokufika ekhaya aze alungise izandla zewotshi yakhe ngokufanelekileyo.”

Fumana ixesha umncedisi ebesebenza kwisicelo:

  1. Ukufumana ixesha lokuhamba kwepakethi ukusuka kumxhasi ukuya kumncedisi: ((Fika - Imvelaphi) - (Hambisa - Yamkela)) / 2
  2. Fumana umahluko phakathi komthengi kunye nexesha leseva:
    Fumana - Imvelaphi - ((Fika - Imvelaphi) - (Thumela - Yamkela)) / 2 =
    2 * Yamkela - 2 * Imvelaphi - Fika + Imvelaphi + Thumela - Fumana =
    Yamkela - Imvelaphi - Fika + Thumela

Songeza ixabiso elifunyenweyo kwixesha lasekuhlaleni kwaye sonwabele ubomi.

Iziphumo

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)

Iluncedo unxibelelwano.

umthombo: www.habr.com

Yongeza izimvo