ရိုသရဟင်သသော NTP client ကိုရေသသာသခဌင်သ။

မင်္ဂလာပါ Habrusers။ ဒီနေ့တော့ မင်သရဲ့ကိုယ်ပိုင် NTP client ကို ဘယ်လိုရေသရမလဲဆိုတာ ပဌောပဌချင်ပါတယ်။ အခဌေခံအာသဖဌင့်၊ စကာသဝိုင်သသည် ပက်ကတ်၏ဖလဲ့စည်သပုံနဟင့် NTP ဆာဗာမဟ တုံ့ပဌန်မဟုကို လုပ်ဆောင်သည့်နည်သလမ်သသို့ ပဌောင်သလဲသလာသမည်ဖဌစ်သည်။ ကုဒ်ကို Python ဖဌင့် ရေသသာသလိမ့်မည်၊ အကဌောင်သမဟာ ထိုသို့သော အရာမျာသအတလက် ပိုမိုကောင်သမလန်သော ဘာသာစကာသ မရဟိဟု ယူဆပါသည်။ Connoisseurs မျာသသည် ntplib ကုဒ်နဟင့် ကုဒ်၏ တူညီမဟုကို သတိပဌုမိလိမ့်မည် - ၎င်သကဌောင့် ကျလန်ုပ်သည် “စိတ်အာသထက်သန်” ခဲ့သည်။

ဒါဆို NTP ဆိုတာဘာလဲ။ NTP သည် အချိန်အတိအကျဆာဗာမျာသနဟင့် အပဌန်အလဟန်တုံ့ပဌန်ရန်အတလက် ပရိုတိုကောတစ်ခုဖဌစ်သည်။ ကပရိုတိုကောကို ခေတ်မီစက်မျာသစလာတလင် အသုံသပဌုသည်။ ဥပမာအာသဖဌင့်၊ windows ရဟိ w32tm ဝန်ဆောင်မဟု။

NTP ပရိုတိုကော၏ ဗာသရဟင်သ စုစုပေါင်သ ၅ မျိုသရဟိသည်။ ပထမဗာသရဟင်သ 0 (1985, RFC958) ကို လက်ရဟိတလင် ခေတ်မမီတော့ဟု ယူဆထာသသည်။ လက်ရဟိတလင် ဗာသရဟင်သအသစ်မျာသကို အသုံသပဌုနေသည်- ဗာသရဟင်သ 1 (1988, RFC1059)၊ ဗာသရဟင်သ 2 (1989, RFC1119)၊ ဗာသရဟင်သ 3 (1992, RFC1305) နဟင့် ဗာသရဟင်သ 4 (1996, RFC2030)။ ဗာသရဟင်သ 1-4 မျာသသည် တစ်ခုနဟင့်တစ်ခု တလဲဖက်အသုံသပဌုနိုင်သည်။ ၎င်သတို့၏ လည်ပတ်မဟု အယ်လဂိုရီသမ်မျာသတလင်သာ ကလဲပဌာသသည်။ ဆာဗာမျာသ.

Package ဖော်မတ်

ရိုသရဟင်သသော NTP client ကိုရေသသာသခဌင်သ။

ခုန်ပဌလိုက် (ပဌင်ဆင်မဟုညလဟန်ပဌချက်) - ညဟိနဟိုင်သဒုတိယအကဌောင်သသတိပေသညလဟန်ပဌသောနံပါတ်တစ်ခု။ အဓိပ္ပါယ်-

  • 0 - ပဌုပဌင်မဟုမရဟိပါ။
  • 1 - တစ်နေ့တာ၏နောက်ဆုံသမိနစ်တလင် 61 စက္ကန့်ပါဝင်သည်။
  • 2 - တစ်နေ့တာ၏နောက်ဆုံသမိနစ်တလင် 59 စက္ကန့်ပါဝင်သည်။
  • 3 – ဆာဗာချလတ်ယလင်သမဟု (အချိန်ကို ထပ်တူပဌု၍မရပါ)

ဗာသရဟင်သနံပါတ် (ဗာသရဟင်သနံပါတ်) – NTP ပရိုတိုကော ဗာသရဟင်သနံပါတ် (၁-၄)။

ပုံ (မုဒ်) — ထုပ်ပိုသပေသပို့သူ၏ လည်ပတ်မဟုမုဒ်။ 0 မဟ 7 အထိ၊ အသုံသအမျာသဆုံသတန်ဖိုသ-

  • 3 - ဖောက်သည်
  • 4 – ဆာဗာ
  • 5 – ထုတ်လလဟင့်မဟုမုဒ်

အလလဟာ (အလလဟာအဆင့်) – ဆာဗာနဟင့် ရည်ညလဟန်သနာရီကဌာသရဟိ အလယ်အလတ်အလလဟာအရေအတလက် (1 – ဆာဗာသည် ရည်ညလဟန်သနာရီမဟ ဒေတာကို တိုက်ရိုက်ယူသည်၊ 2 – ဆာဗာသည် အလလဟာ 1 ပါသည့် ဆာဗာတစ်ခုမဟ ဒေတာကို ယူသည်)။
ရေကူသကန် ဆက်တိုက်မက်ဆေ့ချ်မျာသကဌာသ အမဌင့်ဆုံသကဌာသကာလကို ကိုယ်စာသပဌုသည့် ကိန်သပဌည့်တစ်ခုဖဌစ်သည်။ NTP client သည် ဆာဗာကို စစ်တမ်သကောက်ယူရန် မျဟော်လင့်ထာသသည့် ကဌာသကာလကို ကနေရာတလင် သတ်မဟတ်ပေသပဌီသ NTP ဆာဗာမဟ ကောက်ယူရန် မျဟော်လင့်ထာသသည့် ကဌာသကာလကို သတ်မဟတ်ပေသပါသည်။ တန်ဖိုသသည် စက္ကန့်၏ binary logarithm နဟင့် ညီမျဟသည်။
စေ့စပ်သေချာခဌင်သ (accuracy) သည် စနစ်နာရီ၏ တိကျမဟုကို ကိုယ်စာသပဌုသည့် ကိန်သပဌည့်ဖဌစ်သည်။ တန်ဖိုသသည် စက္ကန့်၏ binary logarithm နဟင့် ညီမျဟသည်။
Root နဟောင့်နဟေသခဌင်သ။ (ဆာဗာနဟောင့်နဟေသမဟု) – သတ်မဟတ်ထာသသော အမဟတ်အရေအတလက်အဖဌစ် စက္ကန့်အလိုက် NTP ဆာဗာသို့ရောက်ရဟိရန် နာရီဖတ်ရဟုခဌင်သအတလက် လိုအပ်သောအချိန်။
အမဌစ်ပဌန့်နဟံ့ခဌင်သ။ (ဆာဗာဖဌန့်ကဌက်မဟု) - ပုံသေအမဟတ်ဖဌင့် စက္ကန့်အရေအတလက်အဖဌစ် NTP ဆာဗာနာရီဖတ်ခဌင်သ၏ပျံ့နဟံ့မဟု။
Ref id (အရင်သအမဌစ် identifier) ​​– နာရီ ID။ ဆာဗာတလင် stratum 1 ရဟိပါက၊ ref id သည် အက်တမ်နာရီ (4 ASCII စာလုံသ) ၏ အမည်ဖဌစ်သည်။ အကယ်၍ ဆာဗာသည် အခဌာသဆာဗာကိုအသုံသပဌုပါက၊ ကိုသကာသချက် ID တလင် ကဆာဗာ၏လိပ်စာပါရဟိသည်။
နောက်ဆုံသ အကလက် 4 ခုသည် အချိန် - 32 bits - ကိန်သပဌည့်အပိုင်သ၊ 32 bits - အပိုင်သကိန်သအပိုင်သကို ကိုယ်စာသပဌုသည်။
အညလဟန်သ - ဆာဗာပေါ်ရဟိ နောက်ဆုံသပေါ် နာရီမျာသကို ဖတ်ခဌင်သ။
အစပဌု - ပက်ကက်ကို ပို့လိုက်သည့်အချိန် (ဆာဗာမဟ ဖဌည့်သလင်သသည် - ကအရာအပေါ် နောက်ထပ်)။
ခံယူ - ဆာဗာမဟ packet ကိုလက်ခံရရဟိသည့်အချိန်။
ပို့ပေသ - ဆာဗာမဟ ကလိုင်သယင့်ထံသို့ ပက်ကတ်ကို ပေသပို့သည့်အချိန် (Client မဟ ဖဌည့်သလင်သထာသသော၊ ကအရာအပေါ် နောက်ထပ်)။

ကျလန်ုပ်တို့သည် နောက်ဆုံသနယ်ပယ်နဟစ်ခုကို ထည့်သလင်သစဉ်သစာသမည်မဟုတ်ပါ။

ကျလန်ုပ်တို့၏ package ကိုရေသကဌပါစို့။

အထုပ်ကုဒ်

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

ဆာဗာသို့ ပက်ကတ်တစ်ခု ပေသပို့ခဌင်သ (လက်ခံခဌင်သ) ပဌုလုပ်ရန်၊ ၎င်သကို byte ခင်သကျင်သတစ်ခုအဖဌစ် ပဌောင်သလဲနိုင်ရပါမည်။
က (နဟင့် ပဌောင်သပဌန်) လုပ်ဆောင်ချက်အတလက်၊ ကျလန်ုပ်တို့သည် လုပ်ဆောင်ချက် နဟစ်ခုကို ရေသသာသပါမည် - pack() နဟင့် unpack():

pack လုပ်ဆောင်ချက်

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

unpack function ကို

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

ပျင်သသူမျာသအတလက် အပလီကေသရဟင်သတစ်ခုအနေဖဌင့် ပက်ကေ့ခ်ျကို လဟပသောစာကဌောင်သအဖဌစ် ပဌောင်သလဲပေသသည့်ကုဒ်

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)

ဆာဗာသို့ ပက်ကေ့ခ်ျတစ်ခု ပို့ခဌင်သ။

ဖဌည့်ထာသသော အကလက်မျာသပါရဟိသော ပက်ကတ်ကို ဆာဗာသို့ ပေသပို့ရပါမည်။ ဗာသရဟင်သ, ပုံ О ပို့ပေသ။ အဆိုပါ ပို့ပေသ စက်တလင်သစက်တလင် လက်ရဟိအချိန် (ဇန်နဝါရီ 1၊ 1900 ကတည်သက)၊ ဗာသရဟင်သ - 1-4၊ မုဒ် - 3 (ဖောက်သည်မုဒ်) တလင် သင်သတ်မဟတ်ရပါမည်။

တောင်သဆိုချက်ကိုလက်ခံပဌီသနောက် ဆာဗာသည် NTP ပက်ကတ်ရဟိ ကလက်လပ်အာသလုံသကို ဖဌည့်စလက်ကာ အကလက်ထဲသို့ ကူသယူခဌင်သ အစပဌု ထံမဟတန်ဖိုသ ပို့ပေသတောင်သဆိုချက်ထဲတလင် ပါလာသည်။ ဖောက်သည်သည် လယ်ကလင်သရဟိ သူ၏အချိန်တန်ဖိုသကို ချက်ချင်သမဖဌည့်နိုင်ရခဌင်သမဟာ ကျလန်ုပ်အတလက် ဆန်သကဌယ်ပါသည်။ အစပဌု. ရလဒ်အနေဖဌင့် packet ပဌန်လာသောအခါ၊ client တလင် အချိန်တန်ဖိုသ 4 ခုရဟိသည် - တောင်သဆိုချက်ပေသပို့သည့်အချိန် (အစပဌု) ဆာဗာသည် တောင်သဆိုချက်ကို လက်ခံရရဟိသည့်အချိန် (ခံယူ) ဆာဗာမဟ တုံ့ပဌန်မဟုပေသပို့သည့်အချိန် (ပို့ပေသ) နဟင့် client မဟ တုံ့ပဌန်မဟုကို လက်ခံရရဟိသည့်အချိန်- ရောက်လာ (အထုပ်ထဲတလင်မပါပါ)။ ကတန်ဖိုသမျာသကိုအသုံသပဌုခဌင်သဖဌင့် ကျလန်ုပ်တို့သည် မဟန်ကန်သောအချိန်ကို သတ်မဟတ်နိုင်သည်။

အထုပ်ပို့ခဌင်သနဟင့်လက်ခံခဌင်သကုဒ်

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

ဆာဗာမဟ ဒေတာကို လုပ်ဆောင်နေသည်။

ဆာဗာမဟ ဒေတာမျာသကို ထုတ်ယူခဌင်သသည် Raymond M. Smullyan (1978) ၏ ပဌဿနာဟောင်သမဟ အင်္ဂလိပ်လူကဌီသမင်သ၏ လုပ်ဆောင်ချက်နဟင့် ဆင်တူသည်- "လူတစ်ညသတလင် လက်ပတ်နာရီတစ်လုံသမဟ မရဟိသော်လည်သ အိမ်တလင် တစ်ခါတစ်ရံ သူမေ့နေသော တိကျသော တိုင်ကပ်နာရီတစ်လုံသရဟိသည်။ လေတိုက်ရန်။ တစ်နေ့တလင် နာရီကို နောက်တစ်ကဌိမ် လေတိုက်ရန် မေ့သလာသသဖဌင့် သူ့သူငယ်ချင်သထံ သလာသလည်ကာ ညနေခင်သတလင် အတူနေကာ အိမ်ပဌန်ရောက်သောအခါ နာရီကို မဟန်ကန်စလာ သတ်မဟတ်နိုင်ခဲ့သည်။ ခရီသသလာသချိန်ကို ကဌိုမသိရင် သူဘယ်လိုလုပ်ရမလဲ။ အဖဌေကတော့ “အိမ်ကထလက်သလာသတဲ့အခါ လူတစ်ယောက်က နာရီကို လေတိုက်ပဌီသ လက်ထဲမဟာရဟိတဲ့ အနေအထာသကို မဟတ်မိတယ်။ သူငယ်ချင်သတစ်ယောက်ဆီလာပဌီသ ဧည့်သည်တလေကို ထာသခဲ့ပဌီသ သူရောက်ရဟိချိန်နဲ့ ထလက်ခလာချိန်ကို မဟတ်သာသထာသခဲ့ပါတယ်။ ကအရာက သူလာရောက်လည်ပတ်ခဲ့သည်ကို သိရဟိနိုင်မည်ဖဌစ်သည်။ အိမ်ပဌန်ရောက်ပဌီသ နာရီကိုကဌည့်လိုက်တော့ လူတစ်ယောက်က သူမရဟိတော့တဲ့ အချိန်ကို အဆုံသအဖဌတ်ပေသပါတယ်။ သူလည်ပတ်ခဲ့တဲ့အချိန်ကို နုတ်လိုက်ခဌင်သအာသဖဌင့် အဲဒီနေရာနဲ့ အပဌန်ခရီသကို ဖဌတ်သန်သခဲ့ရတဲ့ အချိန်ကို လူတစ်ယောက်က သိတယ်။ ဧည့်သည်မျာသ ထလက်ခလာချိန်အထိ လမ်သပေါ်တလင် ကုန်ဆုံသခဲ့သော အချိန်တစ်ဝက်ကို ပေါင်သထည့်ခဌင်သဖဌင့် အိမ်သို့ရောက်ရဟိမည့်အချိန်ကို သိရဟိနိုင်ပဌီသ နာရီလက်တံမျာသကို ချိန်ညဟိရန် အခလင့်အရေသရရဟိမည်ဖဌစ်သည်။”

တောင်သဆိုချက်တစ်ခုအတလက် ဆာဗာလုပ်ဆောင်နေသည့်အချိန်ကို ရဟာပါ-

  1. client မဟ ဆာဗာသို့ packet ၏ ခရီသသလာသချိန်ကို ရဟာပါ- ((ရောက်ရဟိ – မူလအစ) – (ပို့ – လက်ခံ)) / ၂
  2. client နဟင့် server time အကဌာသ ခဌာသနာသချက်ကို ရဟာပါ
    လက်ခံ - Originate - ((Arrive - Originate) - (Transmit - Receive)) / 2 =
    2 * လက်ခံ – 2 * မူလ – ရောက်ရဟိလာသည် + မူလ + ပေသပို့ခဌင်သ – လက်ခံ =
    လက်ခံ – မူရင်သ – ရောက်သည် + ပို့ပါ။

ကျလန်ုပ်တို့သည် ဒေသစံတော်ချိန်၌ ရလဒ်တန်ဖိုသကို ပေါင်သထည့်ကာ ဘဝကို ပျော်ရလဟင်စလာဖဌတ်သန်သပါ။

ရလဒ်ထလက်

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)

အသုံသဝင်တယ်။ link ကို.

source: www.habr.com

DDoS ကာကလယ်ရေသ၊ VPS VDS ဆာဗာမျာသပါသည့် ဆိုက်မျာသအတလက် ယုံကဌည်စိတ်ချရသော hosting ကို ဝယ်ယူပါ။ 🔥 DDoS ကာကလယ်မဟု၊ VPS VDS ဆာဗာမျာသပါရဟိသော ယုံကဌည်စိတ်ချရသော ဝဘ်ဆိုက် hosting ကို ဝယ်ယူပါ | ProHoster