ПишСм простой NTP ΠΊΠ»ΠΈΠ΅Π½Ρ‚

ЗдравствуйтС, Ρ…Π°Π±Ρ€Π°ΡŽΠ·Π΅Ρ€Ρ‹. БСгодня я Ρ…ΠΎΡ‡Ρƒ Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ свой ΠΏΡ€ΠΎΡΡ‚Π΅Π½ΡŒΠΊΠΈΠΉ NTP ΠΊΠ»ΠΈΠ΅Π½Ρ‚. Π’ основном, Ρ€Π°Π·Π³ΠΎΠ²ΠΎΡ€ Π·Π°ΠΉΠ΄Π΅Ρ‚ ΠΎ структурС ΠΏΠ°ΠΊΠ΅Ρ‚Π° ΠΈ способС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΎΡ‚Π²Π΅Ρ‚Π° с NTP сСрвСра. Код Π±ΡƒΠ΄Π΅Ρ‚ написан Π½Π° ΠΏΠΈΡ‚ΠΎΠ½Π΅, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΌΠ½Π΅ каТСтся, Π»ΡƒΡ‡ΡˆΠ΅Π³ΠΎ языка для ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹Ρ… Π²Π΅Ρ‰Π΅ΠΉ просто Π½Π΅ Π½Π°ΠΉΡ‚ΠΈ. Π—Π½Π°Ρ‚ΠΎΠΊΠΈ обратят Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° ΡΡ…ΠΎΠΆΠ΅ΡΡ‚ΡŒ ΠΊΠΎΠ΄Π° с ΠΊΠΎΠ΄ΠΎΠΌ ntplib β€” я «вдохновлялся» ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΈΠΌ.

Π˜Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ Π²ΠΎΠΎΠ±Ρ‰Π΅ Ρ‚Π°ΠΊΠΎΠ΅ NTP? NTP – ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» взаимодСйствия с сСрвСрами Ρ‚ΠΎΡ‡Π½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ. Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π²ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΡ… соврСмСнных ΠΌΠ°ΡˆΠΈΠ½Π°Ρ…. НапримСр, слуТба w32tm Π² windows.

ВсСго сущСствуСт 5 вСрсий NTP ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Π°. ΠŸΠ΅Ρ€Π²Π°Ρ, 0-я вСрсия (1985 Π³, RFC958)), Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ считаСтся ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠ΅ΠΉ. БСйчас ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Π±ΠΎΠ»Π΅Π΅ Π½ΠΎΠ²Ρ‹Π΅, 1-я (1988, RFC1059), 2-я(1989, RFC1119), 3-я(1992, RFC1305) ΠΈ 4-я(1996, RFC2030). 1-4 вСрсии ΡΠ²Π»ΡΡŽΡ‚ΡΡ совмСстимыми Π΄Ρ€ΡƒΠ³ с Π΄Ρ€ΡƒΠ³ΠΎΠΌ, ΠΎΠ½ΠΈ ΠΎΡ‚Π»ΠΈΡ‡Π°ΡŽΡ‚ΡΡ лишь Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ°ΠΌΠΈ Ρ€Π°Π±ΠΎΡ‚Ρ‹ сСрвСров.

Π€ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠ°ΠΊΠ΅Ρ‚Π°

ПишСм простой NTP ΠΊΠ»ΠΈΠ΅Π½Ρ‚

Leap indicator (ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ†ΠΈΠΈ) β€” число, ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰Π΅Π΅ ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎ сСкундС ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ†ΠΈΠΈ. Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:

  • 0 – Π½Π΅Ρ‚ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ†ΠΈΠΈ
  • 1 – послСдняя ΠΌΠΈΠ½ΡƒΡ‚Π° дня содСрТит 61 сСкунду
  • 2 – послСдняя ΠΌΠΈΠ½ΡƒΡ‚Π° дня содСрТит 59 сСкунд
  • 3 – Π½Π΅ΠΈΡΠΏΡ€Π°Π²Π½ΠΎΡΡ‚ΡŒ сСрвСра (врСмя Π½Π΅ синхронизировано)

Version number (Π½ΠΎΠΌΠ΅Ρ€ вСрсии) – Π½ΠΎΠΌΠ΅Ρ€ вСрсии ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Π° NTP (1-4).

Mode (Ρ€Π΅ΠΆΠΈΠΌ) β€” Ρ€Π΅ΠΆΠΈΠΌ Ρ€Π°Π±ΠΎΡ‚Ρ‹ отправитСля ΠΏΠ°ΠΊΠ΅Ρ‚Π°. Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΎΡ‚ 0 Π΄ΠΎ 7, Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ частыС:

  • 3 – ΠΊΠ»ΠΈΠ΅Π½Ρ‚
  • 4 – сСрвСр
  • 5 – ΡˆΠΈΡ€ΠΎΠΊΠΎΠ²Π΅Ρ‰Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ

Stratum (ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ наслоСния) – количСство ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹Ρ… слоСв ΠΌΠ΅ΠΆΠ΄Ρƒ сСрвСром ΠΈ эталонными часами (1 – сСрвСр Π±Π΅Ρ€Π΅Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ нСпосрСдствСнно с эталонных часов, 2 – сСрвСр Π±Π΅Ρ€Π΅Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ с сСрвСра с ΡƒΡ€ΠΎΠ²Π½Π΅ΠΌ 1 ΠΈ Ρ‚.Π΄.).
Pool β€” Ρ†Π΅Π»ΠΎΠ΅ число со Π·Π½Π°ΠΊΠΎΠΌ, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π΅Π΅ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π» ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ сообщСниями. NTP-ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ здСсь ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π», с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΎΠ½ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅Ρ‚ ΠΎΠΏΡ€Π°ΡˆΠΈΠ²Π°Ρ‚ΡŒ сСрвСр, Π° NTP-сСрвСр – ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π», с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΎΠ½ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΅Π³ΠΎ ΠΎΠΏΡ€Π°ΡˆΠΈΠ²Π°Π»ΠΈ. Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Ρ€Π°Π²Π½ΠΎ Π΄Π²ΠΎΠΈΡ‡Π½ΠΎΠΌΡƒ Π»ΠΎΠ³Π°Ρ€ΠΈΡ„ΠΌΡƒ сСкунд.
Precision (Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ) β€” Ρ†Π΅Π»ΠΎΠ΅ число со Π·Π½Π°ΠΊΠΎΠΌ, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π΅Π΅ Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ систСмных часов. Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Ρ€Π°Π²Π½ΠΎ Π΄Π²ΠΎΠΈΡ‡Π½ΠΎΠΌΡƒ Π»ΠΎΠ³Π°Ρ€ΠΈΡ„ΠΌΡƒ сСкунд.
Root delay (Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° сСрвСра) – врСмя, Π·Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ показания часов доходят Π΄ΠΎ NTP-сСрвСра, ΠΊΠ°ΠΊ число сСкунд с фиксированной Ρ‚ΠΎΡ‡ΠΊΠΎΠΉ.
Root dispersion (разброс ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΈΠΉ сСрвСра) β€” разброс ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΈΠΉ часов NTP-сСрвСра ΠΊΠ°ΠΊ число сСкунд с фиксированной Ρ‚ΠΎΡ‡ΠΊΠΎΠΉ.
Ref id (ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ источника) – id часов. Если сСрвСр ΠΈΠΌΠ΅Π΅Ρ‚ стратум 1, Ρ‚ΠΎ ref id – Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Π°Ρ‚ΠΎΠΌΠ½Ρ‹Ρ… часов (4 ASCII символа). Если сСрвСр ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π΄Ρ€ΡƒΠ³ΠΎΠΉ сСрвСр, Ρ‚ΠΎ Π² ref id записан адрСс этого сСрвСра.
ПослСдниС 4 поля ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ ΠΈΠ· сСбя врСмя – 32 Π±ΠΈΡ‚Π° – цСлая Ρ‡Π°ΡΡ‚ΡŒ, 32 Π±ΠΈΡ‚Π° – дробная Ρ‡Π°ΡΡ‚ΡŒ.
Reference β€” послСдниС показания часов Π½Π° сСрвСрС.
Originate – врСмя, ΠΊΠΎΠ³Π΄Π° ΠΏΠ°ΠΊΠ΅Ρ‚ Π±Ρ‹Π» ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ (заполняСтся сСрвСром – ΠΎΠ± этом Π½ΠΈΠΆΠ΅).
Receive – врСмя получСния ΠΏΠ°ΠΊΠ΅Ρ‚Π° сСрвСром.
Transmit – врСмя ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π° с сСрвСра ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρƒ (заполняСтся ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠΌ, ΠΎΠ± этом Ρ‚ΠΎΠΆΠ΅ Π½ΠΈΠΆΠ΅).

Π”Π²Π° послСдних поля Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ.

НапишСм наш ΠΏΠ°ΠΊΠ΅Ρ‚:

Код ΠΏΠ°ΠΊΠ΅Ρ‚Π°

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

Ѐункция 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

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)

ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΏΠ°ΠΊΠ΅Ρ‚Π° Π½Π° сСрвСр

На сСрвСр Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚ с Π·Π°ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹ΠΌΠΈ полями Version, Mode ΠΈ Transmit. Π’ Transmit Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ врСмя Π½Π° локальной машинС (количСство сСкунд с 1 января 1900 Π³), вСрсия β€” любая ΠΈΠ· 1-4, Ρ€Π΅ΠΆΠΈΠΌ β€” 3 (Ρ€Π΅ΠΈΠΆΠΌ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°).

Π‘Π΅Ρ€Π²Π΅Ρ€, приняв запрос, заполняСт Π² NTP-ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ всС поля, скопировав Π² ΠΏΠΎΠ»Π΅ Originate Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ· Transmit, ΠΏΡ€ΠΈΡˆΠ΅Π΄ΡˆΠ΅Π΅ Π² запросС. Для мСня являСтся Π·Π°Π³Π°Π΄ΠΊΠΎΠΉ, ΠΏΠΎΡ‡Π΅ΠΌΡƒ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ сразу Π·Π°ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ своСго Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Π² ΠΏΠΎΠ»Π΅ Originate. Π’ ΠΈΡ‚ΠΎΠ³Π΅, ΠΊΠΎΠ³Π΄Π° ΠΏΠ°ΠΊΠ΅Ρ‚ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ, Ρƒ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° Π΅ΡΡ‚ΡŒ 4 значСния Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ – врСмя ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ запроса (Originate), врСмя получСния запроса сСрвСром (Receive), врСмя ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ ΠΎΡ‚Π²Π΅Ρ‚Π° сСрвСром (Transmit) ΠΈ врСмя получСния ΠΎΡ‚Π²Π΅Ρ‚Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠΌ – Arrive (Π½Π΅Ρ‚ Π² ΠΏΠ°ΠΊΠ΅Ρ‚Π΅). Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ этих Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΠ΅ врСмя.

Код ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ ΠΈ получСния ΠΏΠ°ΠΊΠ΅Ρ‚Π°

# 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. Находим врСмя ΠΏΡƒΡ‚ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π° ΠΎΡ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° ΠΊ сСрвСру: ((Arrive – Originate) β€” (Transmit – Receive)) / 2
  2. Находим Ρ€Π°Π·Π½ΠΈΡ†Ρƒ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° ΠΈ сСрвСра:
    Receive β€” Originate β€” ((Arrive – Originate) β€” (Transmit – Receive)) / 2 =
    2 * Receive β€” 2 * Originate – Arrive + Originate + Transmit – Receive =
    Receive – Originate – Arrive + Transmit

ДобавляСм ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΊ Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΠΎΠΌΡƒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΈ радуСмся ΠΆΠΈΠ·Π½ΠΈ.

Π’Ρ‹Π²ΠΎΠ΄ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°

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)

ПолСзная ссылка.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com