рдПрдХ рд╕рд╛рдзрд╛рд░рдг NTP рдЧреНрд░рд╛рд╣рдХ рд▓реЗрдЦреНрджреИ

рдирдорд╕реНрддреЗ, Habrausersред рдЖрдЬ рдо рддрдкрд╛рдЗрдБрдХреЛ рдЖрдлреНрдиреИ рд╕рд╛рдзрд╛рд░рдг NTP рдЧреНрд░рд╛рд╣рдХ рдХрд╕рд░реА рд▓реЗрдЦреНрдиреЗ рдмрд╛рд░реЗ рдХреБрд░рд╛ рдЧрд░реНрди рдЪрд╛рд╣рдиреНрдЫреБред рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛, рдХреБрд░рд╛рдХрд╛рдиреА рдкреНрдпрд╛рдХреЗрдЯрдХреЛ рд╕рдВрд░рдЪрдирд╛ рд░ NTP рд╕рд░реНрднрд░рдмрд╛рдЯ рдХрд╕рд░реА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╢реЛрдзрди рдЧрд░рд┐рдиреНрдЫ рднрдиреНрдиреЗрдорд╛ рдкрд░рд┐рдгрдд рд╣реБрдиреЗрдЫред рдХреЛрдб рдкрд╛рдЗрдердирдорд╛ рд▓реЗрдЦрд┐рдиреЗрдЫ, рдХрд┐рдирднрдиреЗ, рдореЗрд░реЛ рд╡рд┐рдЪрд╛рд░рдорд╛, рддреНрдпрд╕реНрддрд╛ рдЪреАрдЬрд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рдХреБрдиреИ рд░рд╛рдореНрд░реЛ рднрд╛рд╖рд╛ рдЫреИрдиред Connoisseurs ntplib рдХреЛрдб рд╕рдВрдЧ рдХреЛрдб рдХреЛ рд╕рдорд╛рдирддрд╛ рдорд╛ рдзреНрдпрд╛рди рджрд┐рдиреЗрдЫ - рдо рдпрд╕рдмрд╛рдЯ "рдкреНрд░реЗрд░рд┐рдд" рдерд┐рдПрдБред

рддреНрдпрд╕реЛрднрдП NTP рд╡рд╛рд╕реНрддрд╡рдорд╛ рдХреЗ рд╣реЛ? NTP рд╕рд╣реА рд╕рдордп рд╕рд░реНрднрд░рд╣рд░реБ рд╕рдВрдЧ рдЕрдиреНрддрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд▓рд╛рдЧреА рдПрдХ рдкреНрд░реЛрдЯреЛрдХрд▓ рд╣реЛред рдпреЛ рдкреНрд░реЛрдЯреЛрдХрд▓ рдзреЗрд░реИ рдЖрдзреБрдирд┐рдХ рдореЗрд╕рд┐рдирд╣рд░реВрдорд╛ рдкреНрд░рдпреЛрдЧ рдЧрд░рд┐рдиреНрдЫред рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, рд╡рд┐рдиреНрдбреЛрдЬрдорд╛ w32tm рд╕реЗрд╡рд╛ред

NTP рдкреНрд░реЛрдЯреЛрдХрд▓рдХреЛ рдХреБрд▓ 5 рд╕рдВрд╕реНрдХрд░рдгрд╣рд░реВ рдЫрдиреНред рдкрд╣рд┐рд▓реЛ, рд╕рдВрд╕реНрдХрд░рдг 0 (1985, RFC958) рд╣рд╛рд▓ рдЕрдкреНрд░рдЪрд▓рд┐рдд рдорд╛рдирд┐рдиреНрдЫред рдирдпрд╛рдБ рд╣рд╛рд▓ рдкреНрд░рдпреЛрдЧ рдЧрд░рд┐рдиреНрдЫ, рдкрд╣рд┐рд▓реЛ (1, RFC1988), рджреЛрд╕реНрд░реЛ (1059, RFC2), рддреЗрд╕реНрд░реЛ (1989, RFC1119) рд░ рдЪреМрдереЛ (3, RFC1992)ред рд╕рдВрд╕реНрдХрд░рдг 1305-4 рдПрдХ рдЕрд░реНрдХрд╛рд╕рдБрдЧ рдорд┐рд▓реНрджреЛ рдЫ, рддрд┐рдиреАрд╣рд░реВ рдХреЗрд╡рд▓ рд╕рд░реНрднрд░рд╣рд░реВрдХреЛ рдПрд▓реНрдЧреЛрд░рд┐рджрдордорд╛ рднрд┐рдиреНрди рд╣реБрдиреНрдЫрдиреНред

рдкреНрдпрд╛рдХреЗрдЬ рдврд╛рдБрдЪрд╛

рдПрдХ рд╕рд╛рдзрд╛рд░рдг NTP рдЧреНрд░рд╛рд╣рдХ рд▓реЗрдЦреНрджреИ

рд▓реАрдк рд╕реВрдЪрдХ (рд╕реБрдзрд╛рд░ рд╕реВрдЪрдХ) рдПрдХ рд╕рдВрдЦреНрдпрд╛ рд╣реЛ рдЬрд╕рд▓реЗ рд▓реАрдк рджреЛрд╕реНрд░реЛ рдЪреЗрддрд╛рд╡рдиреАрд▓рд╛рдИ рд╕рдВрдХреЗрдд рдЧрд░реНрджрдЫред рдЕрд░реНрде:

  • 0 - рдХреБрдиреИ рд╕реБрдзрд╛рд░ рдЫреИрди
  • 1 - рджрд┐рдирдХреЛ рдЕрдиреНрддрд┐рдо рдорд┐рдиреЗрдЯрдорд╛ 61 рд╕реЗрдХреЗрдиреНрдб рд╣реБрдиреНрдЫ
  • реи - рджрд┐рдирдХреЛ рдЕрдиреНрддрд┐рдо рдорд┐рдиреЗрдЯрдорд╛ релреп рд╕реЗрдХреЗрдиреНрдб рд╣реБрдиреНрдЫ
  • 3 - рд╕рд░реНрднрд░ рдЦрд░рд╛рдмреА (рд╕рдордп рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬ рдЧрд░рд┐рдПрдХреЛ рдЫреИрди)

рд╕рдВрд╕реНрдХрд░рдг рд╕рдВрдЦреНрдпрд╛ (рд╕рдВрд╕реНрдХрд░рдг рдирдореНрдмрд░) тАУ NTP рдкреНрд░реЛрдЯреЛрдХрд▓ рд╕рдВрд╕реНрдХрд░рдг рдирдореНрдмрд░ (1-4)ред

рдореЛрдб (рдореЛрдб) - рдкреНрдпрд╛рдХреЗрдЯ рдкреНрд░реЗрд╖рдХрдХреЛ рд╕рдЮреНрдЪрд╛рд▓рди рдореЛрдбред реж рджреЗрдЦрд┐ рен рд╕рдореНрдордХреЛ рдорд╛рди, рд╕рдмреИрднрдиреНрджрд╛ рд╕рд╛рдорд╛рдиреНрдп:

  • 3 - рдЧреНрд░рд╛рд╣рдХ
  • 4 - рд╕рд░реНрднрд░
  • 5 - рдкреНрд░рд╕рд╛рд░рдг рдореЛрдб

рд╕реНрдЯреНрд░реНрдпрд╛рдЯрдо (рд▓реЗрдпрд░рд┐рдЩ рд╕реНрддрд░) - рд╕рд░реНрднрд░ рд░ рд╕рдиреНрджрд░реНрдн рдШрдбреА рдмреАрдЪрдХреЛ рдордзреНрдпрд╡рд░реНрддреА рддрд╣рд╣рд░реВрдХреЛ рд╕рдВрдЦреНрдпрд╛ (1 - рд╕рд░реНрднрд░рд▓реЗ рд╕рдиреНрджрд░реНрдн рдШрдбреАрдмрд╛рдЯ рд╕реАрдзреИ рдбреЗрдЯрд╛ рд▓рд┐рдиреНрдЫ, 2 - рд╕рд░реНрднрд░рд▓реЗ рд╕реНрддрд░ 1, рдЖрджрд┐рдХреЛ рд╕рд╛рде рд╕рд░реНрднрд░рдмрд╛рдЯ рдбреЗрдЯрд╛ рд▓рд┐рдиреНрдЫ)ред
рдкреВрд▓ рд▓рдЧрд╛рддрд╛рд░ рд╕рдиреНрджреЗрд╢рд╣рд░реВ рдмреАрдЪрдХреЛ рдЕрдзрд┐рдХрддрдо рдЕрдиреНрддрд░рд╛рд▓ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдЧрд░реНрдиреЗ рдПрдХ рд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд рдкреВрд░реНрдгрд╛рдВрдХ рд╣реЛред NTP рдХреНрд▓рд╛рдЗрдиреНрдЯрд▓реЗ рд╕рд░реНрднрд░рдорд╛ рдкреЛрд▓ рдЧрд░реНрдиреЗ рдЕрдкреЗрдХреНрд╖рд╛ рдЧрд░реЗрдХреЛ рдЕрдиреНрддрд░рд╛рд▓ рдпрд╣рд╛рдБ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЧрд░реНрджрдЫ, рд░ NTP рд╕рд░реНрднрд░рд▓реЗ рдкреЛрд▓ рд╣реБрдиреЗ рдЕрдкреЗрдХреНрд╖рд╛ рдЧрд░реЗрдХреЛ рдЕрдиреНрддрд░рд╛рд▓ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЧрд░реНрджрдЫред рдорд╛рди рд╕реЗрдХреЗрдиреНрдбрдХреЛ рдмрд╛рдЗрдирд░реА рд▓реЛрдЧрд╛рд░рд┐рджрдо рдмрд░рд╛рдмрд░ рдЫред
рд╕рдЯреАрдХ (рд╢реБрджреНрдзрддрд╛) рдкреНрд░рдгрд╛рд▓реА рдШрдбреАрдХреЛ рд╢реБрджреНрдзрддрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдЧрд░реНрдиреЗ рдПрдХ рд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд рдкреВрд░реНрдгрд╛рдВрдХ рд╣реЛред рдорд╛рди рд╕реЗрдХреЗрдиреНрдбрдХреЛ рдмрд╛рдЗрдирд░реА рд▓реЛрдЧрд╛рд░рд┐рджрдо рдмрд░рд╛рдмрд░ рдЫред
рдореВрд▓ рдврд┐рд▓рд╛рдЗ (рд╕рд░реНрднрд░ рд╡рд┐рд▓рдореНрдмрддрд╛) рд╕реЗрдХреЗрдиреНрдбрдХреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд-рдмрд┐рдиреНрджреБ рд╕рдВрдЦреНрдпрд╛рдХреЛ рд░реВрдкрдорд╛, NTP рд╕рд░реНрднрд░рдорд╛ рдкреБрдЧреНрди рдШрдбреАрд▓реЗ рд▓рд╛рдЧреНрдиреЗ рд╕рдордп рд╣реЛред
рдЬрд░рд╛ рдлреИрд▓рд╛рд╡рдЯ (рд╕рд░реНрднрд░ рд╕реНрдХреНрдпрд╛рдЯрд░) - рд╕реЗрдХреЗрдиреНрдбрдХреЛ рдирд┐рд╢реНрдЪрд┐рдд-рдмрд┐рдиреНрджреБ рд╕рдВрдЦреНрдпрд╛рдХреЛ рд░реВрдкрдорд╛ NTP рд╕рд░реНрднрд░ рдШрдбреАрдХреЛ рд╕реНрдХреНрдпрд╛рдЯрд░ред
рд╕рдиреНрджрд░реНрдн рдЖрдИрдбреА (рд╕реНрд░реЛрдд рдкрд╣рд┐рдЪрд╛рдирдХрд░реНрддрд╛) - рдШрдбреА рдЖрдИрдбреАред рдпрджрд┐ рд╕рд░реНрднрд░рдорд╛ рд╕реНрдЯреНрд░реНрдпрд╛рдЯрдо 1 рдЫ рднрдиреЗ, рддреНрдпрд╕рдкрдЫрд┐ рд░реЗрдл рдЖрдИрдбреА рдкрд░рдорд╛рдгреБ рдШрдбреАрдХреЛ рдирд╛рдо рд╣реЛ (4 ASCII рд╡рд░реНрдгрд╣рд░реВ)ред рдпрджрд┐ рд╕рд░реНрднрд░рд▓реЗ рдЕрд░реНрдХреЛ рд╕рд░реНрднрд░ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдЫ рднрдиреЗ, рд░реЗрдл рдЖрдЗрдбреАрд▓реЗ рдпреЛ рд╕рд░реНрднрд░рдХреЛ рдареЗрдЧрд╛рдирд╛ рд╕рдорд╛рд╡реЗрд╢ рдЧрд░реНрджрдЫред
рдЕрдиреНрддрд┐рдо 4 рдХреНрд╖реЗрддреНрд░рд╣рд░реВрд▓реЗ рд╕рдордп рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдЧрд░реНрджрдЫ - 32 рдмрд┐рдЯ - рдкреВрд░реНрдгрд╛рдВрдХ рднрд╛рдЧ, 32 рдмрд┐рдЯ - рдЕрдВрд╢рд╛рддреНрдордХ рднрд╛рдЧред
рд╕рдВрджрд░реНрдн - рд╕рд░реНрднрд░рдорд╛ рдирд╡реАрдирддрдо рдШрдбреА рдкрдврд╛рдЗрд╣рд░реВред
рдЙрддреНрдкрддреНрддрд┐ - рд╕рдордп рдЬрдм рдкреНрдпрд╛рдХреЗрдЯ рдкрдард╛рдЗрдпреЛ (рд╕рд░реНрднрд░ рджреНрд╡рд╛рд░рд╛ рднрд░рд┐рдПрдХреЛ - рддрд▓ рдердкрдорд╛)ред
рдкреНрд░рд╛рдкреНрдд - рд╕рд░реНрднрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрдпрд╛рдХреЗрдЯ рдкреНрд░рд╛рдкреНрдд рднрдПрдХреЛ рд╕рдордпред
рдкреНрд░реЗрд╖рд┐рдд - рд╕рдордп рдЬрдм рдкреНрдпрд╛рдХреЗрдЯ рд╕рд░реНрднрд░рдмрд╛рдЯ рдЧреНрд░рд╛рд╣рдХрд▓рд╛рдИ рдкрдард╛рдЗрдПрдХреЛ рдерд┐рдпреЛ (рдЧреНрд░рд╛рд╣рдХ рджреНрд╡рд╛рд░рд╛ рднрд░рд┐рдПрдХреЛ, рддрд▓ рдердкрдорд╛)ред

рд╣рд╛рдореА рдЕрдиреНрддрд┐рдо рджреБрдИ рдХреНрд╖реЗрддреНрд░рд╣рд░реВ рд╡рд┐рдЪрд╛рд░ рдЧрд░реНрджреИрдиреМрдВред

рд╣рд╛рдореНрд░реЛ рдкреНрдпрд╛рдХреЗрдЬ рд▓реЗрдЦреМрдВ:

рдкреНрдпрд╛рдХреЗрдЬ рдХреЛрдб

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

рд╕рд░реНрднрд░рдорд╛ рдкреНрдпрд╛рдХреЗрдЯ рдкрдард╛рдЙрди (рд░ рдкреНрд░рд╛рдкреНрдд) рдЧрд░реНрди, рд╣рд╛рдореАрд▓реЗ рдпрд╕рд▓рд╛рдИ рдмрд╛рдЗрдЯрд╣рд░реВрдХреЛ рдПрд░реНрд░реЗрдорд╛ рдмрджрд▓реНрди рд╕рдХреНрд╖рдо рд╣реБрдиреБрдкрд░реНрджрдЫред
рдпреЛ (рд░ рдЙрд▓реНрдЯреЛ) рд╕рдЮреНрдЪрд╛рд▓рдирдХреЛ рд▓рд╛рдЧрд┐, рд╣рд╛рдореА рджреБрдИ рдкреНрд░рдХрд╛рд░реНрдпрд╣рд░реВ рд▓реЗрдЦреНрдиреЗрдЫреМрдВ - pack() рд░ unpack():

рдкреНрдпрд╛рдХ рдкреНрд░рдХрд╛рд░реНрдп

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

рдЕрдирдкреНрдпрд╛рдХ рдкреНрд░рдХрд╛рд░реНрдп

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 рдкреНрдпрд╛рдХреЗрдЯрдорд╛ рд╕рдмреИ рдлрд┐рд▓реНрдбрд╣рд░реВ рднрд░реНрдЫ, рдлрд┐рд▓реНрдбрдорд╛ рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдЧрд░реНрджреИ рдЙрддреНрдкрддреНрддрд┐ рдмрд╛рдЯ рдореВрд▓реНрдп рдкреНрд░реЗрд╖рд┐рдд, рдЬреБрди рдЕрдиреБрд░реЛрдзрдорд╛ рдЖрдПрдХреЛ рдерд┐рдпреЛ ред рдпреЛ рдореЗрд░реЛ рд▓рд╛рдЧрд┐ рд░рд╣рд╕реНрдп рд╣реЛ рдХрд┐рди рдЧреНрд░рд╛рд╣рдХрд▓реЗ рддреБрд░реБрдиреНрддреИ рдлрд┐рд▓реНрдбрдорд╛ рдЖрдлреНрдиреЛ рд╕рдордпрдХреЛ рдореВрд▓реНрдп рднрд░реНрди рд╕рдХреНрджреИрди рдЙрддреНрдкрддреНрддрд┐ред рдирддрд┐рдЬрд╛рдХреЛ рд░реВрдкрдорд╛, рдЬрдм рдкреНрдпрд╛рдХреЗрдЯ рдлрд┐рд░реНрддрд╛ рдЖрдЙрдБрдЫ, рдЧреНрд░рд╛рд╣рдХрд╕рдБрдЧ 4 рд╕рдордп рдорд╛рдирд╣рд░реВ рдЫрдиреН - рдЕрдиреБрд░реЛрдз рдкрдард╛рдЗрдПрдХреЛ рд╕рдордп (рдЙрддреНрдкрддреНрддрд┐), рд╕рд░реНрднрд░рд▓реЗ рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рдЧрд░реЗрдХреЛ рд╕рдордп (рдкреНрд░рд╛рдкреНрдд), рд╕рд░реНрднрд░рд▓реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкрдард╛рдПрдХреЛ рд╕рдордп (рдкреНрд░реЗрд╖рд┐рдд) рд░ рдЧреНрд░рд╛рд╣рдХ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдиреЗ рд╕рдордп - рдЖрдЧрдорди (рдкреНрдпрд╛рдХреЗрдЬрдорд╛ рдЫреИрди)ред рдпреА рдорд╛рдирд╣рд░реВрд╕рдБрдЧ рд╣рд╛рдореА рд╕рд╣реА рд╕рдордп рд╕реЗрдЯ рдЧрд░реНрди рд╕рдХреНрдЫреМрдВред

рдкреНрдпрд╛рдХреЗрдЬ рдкрдард╛рдЙрдиреЗ рд░ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдиреЗ рдХреЛрдб

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

рд╕рд░реНрднрд░рдмрд╛рдЯ рдбрд╛рдЯрд╛ рдкреНрд░рд╢реЛрдзрди рдЧрд░реНрджреИ

рд╕рд░реНрднрд░рдмрд╛рдЯ рдбрд╛рдЯрд╛рдХреЛ рдкреНрд░рд╢реЛрдзрди рд░реЗрдордиреНрдб рдПрдо. рд╕реНрдорд╛рд▓рд┐рдпрди (1978) рдХреЛ рдкреБрд░рд╛рдиреЛ рд╕рдорд╕реНрдпрд╛рдмрд╛рдЯ рдЕрдВрдЧреНрд░реЗрдЬреА рд╕рдЬреНрдЬрдирдХреЛ рдХрд╛рд░реНрдпрд╣рд░реВ рдЬрд╕реНрддреИ рдЫ: "рдПрдЙрдЯрд╛ рд╡реНрдпрдХреНрддрд┐рд╕рдБрдЧ рдирд╛рдбреА рдШрдбреА рдерд┐рдПрди, рддрд░ рдШрд░рдорд╛ рдПрдХ рд╕рдЯреАрдХ рдкрд░реНрдЦрд╛рд▓ рдШрдбреА рдерд┐рдпреЛ, рдЬреБрди рдЙрд╕рд▓реЗ рдХрд╣рд┐рд▓реЗрдХрд╛рд╣реАрдБ рд╣рд╛рд╡рд╛ рдмрд┐рд░реНрд╕рдиреНрдЫред рдПрдХ рджрд┐рди, рдлреЗрд░рд┐ рдШрдбреА рд╕реБрд░реБ рдЧрд░реНрди рдмрд┐рд░реНрд╕реЗрд░, рдЙрдиреА рдЖрдлреНрдиреЛ рд╕рд╛рдереАрд▓рд╛рдИ рднреЗрдЯреНрди рдЧрдП, рдЙрдиреАрд╕рдБрдЧ рд╕рд╛рдБрдЭ рдмрд┐рддрд╛рдП, рд░ рдЬрдм рдЙрдиреА рдШрд░ рдлрд░реНрдХрд┐рдП, рдЙрдирд▓реЗ рдШрдбреА рдареАрдХрд╕рдБрдЧ рд╕реЗрдЯ рдЧрд░реНрди рд╕рдХреЗред рдпрд╛рддреНрд░рд╛рдХреЛ рд╕рдордп рдкрд╣рд┐рд▓реНрдпреИ рдерд╛рд╣рд╛ рдирднрдПрдХреЛ рдЦрдгреНрдбрдорд╛ рдЙрд╕рд▓реЗ рдпреЛ рдХрд╕рд░реА рдЧрд░реНрдиреЗ ? рдЬрд╡рд╛рдл рдЫ: "рдШрд░ рдЫреЛрдбреЗрд░, рдПрдХ рд╡реНрдпрдХреНрддрд┐рд▓реЗ рдШрдбреА рдШреБрдорд╛рдЙрдБрдЫ рд░ рд╣рд╛рддрдХреЛ рд╕реНрдерд┐рддрд┐ рд╕рдореНрдЭрдиреНрдЫред рдПрдХрдЬрдирд╛ рд╕рд╛рдереАрд╕рдБрдЧ рдЖрдЙрдБрджрд╛ рд░ рдкрд╛рд╣реБрдирд╛рд╣рд░реВрд▓рд╛рдИ рдЫреЛрдбреЗрд░, рдЙрд╕рд▓реЗ рдЖрдлреНрдиреЛ рдЖрдЧрдорди рд░ рдкреНрд░рд╕реНрдерд╛рдирдХреЛ рд╕рдордп рдиреЛрдЯ рдЧрд░реНрджрдЫред рдпрд╕рд▓реЗ рдЙрд╕рд▓рд╛рдИ рдХрддрд┐ рд▓рд╛рдореЛ рд╕рдордп рдЯрд╛рдврд╛ рдерд┐рдпреЛ рднрдиреЗрд░ рдкрддреНрддрд╛ рд▓рдЧрд╛рдЙрди рдЕрдиреБрдорддрд┐ рджрд┐рдиреНрдЫред рдШрд░ рдлрд░реНрдХреЗрд░ рд░ рдШрдбреА рд╣реЗрд░реЗрд░, рдПрдХ рд╡реНрдпрдХреНрддрд┐рд▓реЗ рдЖрдлреНрдиреЛ рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐рдХреЛ рдЕрд╡рдзрд┐ рдирд┐рд░реНрдзрд╛рд░рдг рдЧрд░реНрджрдЫред рдпрд╕ рд╕рдордпрдмрд╛рдЯ рдЙрд╕рд▓реЗ рднреНрд░рдордгрдорд╛ рдмрд┐рддрд╛рдПрдХрд╛ рд╕рдордпрд▓рд╛рдИ рдШрдЯрд╛рдПрд░, рд╡реНрдпрдХреНрддрд┐рд▓реЗ рддреНрдпрд╣рд╛рдБ рд░ рдкрдЫрд╛рдбрд┐ рдмрд╛рдЯреЛрдорд╛ рдмрд┐рддрд╛рдПрдХреЛ рд╕рдордп рдкрддреНрддрд╛ рд▓рдЧрд╛рдЙрдБрджрдЫред рд╕рдбрдХрдорд╛ рдмрд┐рддрд╛рдПрдХреЛ рд╕рдордпрдХреЛ рдЖрдзрд╛ рдкрд╛рд╣реБрдирд╛ рдмрд┐рджрд╛рдХреЛ рд╕рдордпрд▓рд╛рдИ рдЬреЛрдбреЗрд░ рдШрд░ рдкреБрдЧреНрдиреЗ рд╕рдордп рдкрддреНрддрд╛ рд▓рдЧрд╛рдЙрдиреЗ рд░ рд╕реЛрд╣реА рдЕрдиреБрд╕рд╛рд░ рдШрдбреАрдХреЛ рд╣рд╛рдд рдорд┐рд▓рд╛рдЙрдиреЗ рдореМрдХрд╛ рдкрд╛рдЙрдБрдЫрдиреН ред

рд╕рд░реНрднрд░рд▓реЗ рдЕрдиреБрд░реЛрдзрдорд╛ рдХрд╛рдо рдЧрд░рд┐рд░рд╣реЗрдХреЛ рд╕рдордп рдкрддреНрддрд╛ рд▓рдЧрд╛рдЙрдиреБрд╣реЛрд╕реН:

  1. рдЧреНрд░рд╛рд╣рдХрдмрд╛рдЯ рд╕рд░реНрднрд░рдорд╛ рдкреНрдпрд╛рдХреЗрдЯ рдпрд╛рддреНрд░рд╛ рд╕рдордп рдЦреЛрдЬреНрджреИ: ((рдЖрдЧрдорди тАУ рдЙрддреНрдкрддреНрддрд┐) тАУ (рдкреНрд░рд╕рд╛рд░рдг тАУ рдкреНрд░рд╛рдкреНрдд)) / реи
  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)

рдЙрдкрдпреЛрдЧреА рд▓рд┐рдЩреНрдХ.

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди