Ukubhala iklayenti le-NTP elilula

Sawubona habrausers. Namuhla ngifuna ukukhuluma ngendlela yokubhala iklayenti lakho elilula le-NTP. Ngokuyisisekelo, ingxoxo izophendukela esakhiweni sephakethe nokuthi impendulo evela kuseva ye-NTP icutshungulwa kanjani. Ikhodi izobhalwa nge-python, ngoba, ngokubona kwami, alukho ulimi olungcono lwezinto ezinjalo. Ongoti bazonaka ukufana kwekhodi nekhodi ye-ntplib - "ngikhuthazwe" yiyo.

Manje yini i-NTP noma kunjalo? I-NTP iyiphrothokholi yokuxhumana namaseva esikhathi. Le protocol isetshenziswa emishinini eminingi yesimanje. Isibonelo, isevisi ye-w32tm kumawindi.

Kunezinguqulo ezi-5 zephrothokholi ye-NTP sezizonke. Eyokuqala, inguqulo engu-0 (1985, RFC958) okwamanje ibhekwa njengengasebenzi. Ezintsha zisetshenziswa njengamanje, 1st (1988, RFC1059), 2nd (1989, RFC1119), 3rd (1992, RFC1305) and 4th (1996, RFC2030). Izinguqulo 1-4 ziyahambisana, zihluka kuphela kuma-algorithms amaseva.

Ifomethi Yephakethe

Ukubhala iklayenti le-NTP elilula

Inkomba ye-Leap (inkomba yokulungisa) inombolo ekhombisa isixwayiso sesibili sokugxuma. Incazelo:

  • 0 - akukho ukulungiswa
  • 1 - umzuzu wokugcina wosuku uqukethe imizuzwana engama-61
  • 2 - umzuzu wokugcina wosuku uqukethe imizuzwana engama-59
  • 3 - ukwehluleka kweseva (isikhathi siphelelwe ukuvumelanisa)

Inombolo yenguqulo (inombolo yenguqulo) – inombolo yenguqulo yephrothokholi ye-NTP (1-4).

Mode (mode) β€” imodi yokusebenza yomthumeli wephakethe. Inani ukusuka ku-0 kuye ku-7, elivame kakhulu:

  • 3 - iklayenti
  • 4 - iseva
  • 5 - imodi yokusakaza

Isigaxa (izinga lesendlalelo) - inani lezendlalelo eziphakathi phakathi kweseva newashi lereferensi (1 - iseva ithatha idatha ngokuqondile ewashi lereferensi, 2 - iseva ithatha idatha kusuka kuseva ngezinga 1, njll.).
ichibi iyinombolo esayiniwe emele umkhawulo wesikhawu phakathi kwemilayezo elandelanayo. Iklayenti le-NTP licacisa lapha isikhawu lapho lilindele ukuvotela iseva, futhi iseva ye-NTP icacisa isikhawu lapho ilindele ukuvota ngaso. Inani lilingana ne-logarithm kanambambili yamasekhondi.
Ukwenza kahle hle (ukunemba) iyinamba esayiniwe emelela ukunemba kwewashi lesistimu. Inani lilingana ne-logarithm kanambambili yamasekhondi.
ukubambezeleka kwezimpande (ukubambezeleka kweseva) isikhathi esisithathayo ukuze iwashi lifinyelele iseva ye-NTP, njengenombolo yephoyinti eligxilile lamasekhondi.
ukuhlakazeka kwezimpande (i-server scatter) - Ukuhlakazeka kwewashi leseva ye-NTP njengenombolo yephoyinti eligxilile lamasekhondi.
I-id yeref (i-id yomthombo) - i-id yokubuka. Uma iseva ine-stratum 1, i-ref id yigama lewashi le-athomu (izinhlamvu ezi-4 ASCII). Uma iseva isebenzisa enye iseva, i-id yeref iqukethe ikheli lale seva.
Izinkambu ezi-4 zokugcina zimelela isikhathi - amabhithi angu-32 - ingxenye ephelele, amabhithi angu-32 - ingxenye eyingxenye.
Izikhombo - iwashi lakamuva kuseva.
Isiqalo - isikhathi lapho iphakethe lithunyelwe (ligcwaliswe yiseva - okuningi kulokho okungezansi).
Thola – isikhathi lapho iphakethe lamukelwe khona yiseva.
Dlulisa - isikhathi lapho iphakethe lithunyelwe lisuka kuseva liya kuklayenti (ligcwaliswe iklayenti, okuningi kulokho okungezansi).

Izinkambu ezimbili zokugcina ngeke zicatshangelwe.

Masibhale iphakheji yethu:

Ikhodi 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 (nokwamukela) iphakethe kuseva, kufanele sikwazi ukuliguqula libe uchungechunge lwamabhayithi.
Kulokhu (kanye nokuhlehla) ukusebenza, sizobhala imisebenzi emibili - pack() futhi unpack():

umsebenzi wephakethe

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

khipha umsebenzi

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 abavilaphayo, njengohlelo lokusebenza - ikhodi eguqula iphakheji ibe yintambo enhle

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)

Ithumela iphakheji kuseva

Thumela iphakethe elinezinkambu ezigcwalisiwe kuseva Inguqulo, Mode ΠΈ Dlulisa. I Dlulisa kufanele ucacise isikhathi samanje emshinini wendawo (inombolo yemizuzwana kusukela ngoJanuwari 1, 1900), inguqulo - noma iyiphi ye-1-4, imodi - 3 (imodi yeklayenti).

Iseva, ngemva kokuthola isicelo, igcwalisa zonke izinkambu ephaketheni le-NTP, ikopishelwe ensimini Isiqalo inani kusuka Dlulisa, eyangena ngesicelo. Kuyimfihlakalo kimi ukuthi kungani iklayenti lingakwazi ukugcwalisa ngokushesha inani lesikhathi salo ensimini Isiqalo. Ngenxa yalokho, lapho iphakethe libuya, iklayenti linamanani wesikhathi esi-4 - isikhathi esithunyelwe ngaso isicelo (Isiqalo), isikhathi iseva ithole ngaso isicelo (Thola), isikhathi iseva ithumele ngaso impendulo (Dlulisa) kanye nesikhathi sokuthola impendulo yikhasimende - Fika (hhayi ephaketheni). Ngala magugu singakwazi ukusetha isikhathi esifanele.

Ikhodi yokuthumela nokwamukela iphakheji

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

Ukucubungula idatha kusuka kuseva

Ukucutshungulwa kwedatha evela kuseva kufana nezenzo zomnumzane oyiNgisi ovela enkingeni endala kaRaymond M. Smallian (1978): β€œUmuntu oyedwa wayengenalo iwashi lesihlakala, kodwa kwakukhona iwashi lasodongeni elinembile ekhaya, alithola. ngezinye izikhathi ukhohlwe umoya. Ngolunye usuku, ekhohlwe ukuqala iwashi futhi, wavakashela umngane wakhe, wachitha ubusuku naye, futhi lapho ebuyela ekhaya, wakwazi ukusetha iwashi ngendlela efanele. Wakwazi kanjani ukwenza lokhu uma isikhathi sokuhamba sasingaziwa kusengaphambili? Impendulo ithi: β€œEphuma endlini, umuntu uvula iwashi abese ekhumbula ukuma kwezandla. Eza kumngane futhi eshiya izivakashi, uphawula isikhathi sokufika nokuhamba kwakhe. Lokhu kumenza akwazi ukuthola ukuthi ubehambe isikhathi esingakanani. Lapho ebuyela ekhaya futhi ebheka iwashi, umuntu unquma ukuthi ungekho isikhathi esingakanani. Esusa kulesi sikhathi isikhathi asichitha evakashile, umuntu uthola isikhathi asichitha emgwaqeni lapho futhi abuye. Ngokungeza ingxenye yesikhathi esichithwa emgwaqeni esikhathini sokushiya izivakashi, uthola ithuba lokuthola isikhathi sokufika ekhaya futhi alungise izandla zewashi lakhe ngokufanele.

Thola isikhathi iseva ibisebenza ngaso esicelweni:

  1. Ukuthola isikhathi sokuhamba kwephakethe kusuka kuklayenti kuya kuseva: ((Fika - Ivela) - (Dlulisa - Yamukela)) / 2
  2. Thola umehluko phakathi kwesikhathi seklayenti nesikhathi seseva:
    Thola - Kwavela - ((Fika - Vele) - (Dlulisa - Yamukela)) / 2 =
    2 * Thola - 2 * Kwavela - Fika + Kwavela + Thumela - Thola =
    Yamukela - Okwangempela - Fika + Dlulisa

Sengeza inani elitholiwe esikhathini sendawo futhi sijabulele ukuphila.

Okukhipha Umphumela

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)

Iwusizo isixhumanisi.

Source: www.habr.com

Engeza amazwana