Декодирование пакетов NTP - PullRequest
0 голосов
/ 14 февраля 2019

В данный момент я пытаюсь декодировать пакет с ntp-сервера.Я пробую это в AutoIT, это простой язык сценариев.

Я нашел некоторый код, но проблема в том, что мне тоже нужны миллисекунды.Код предоставляет только секунды.

Вот код, который я нашел:

Local $ntpServer = 'pool.ntp.org'

UDPStartup()

Dim $socket = UDPOpen(TCPNameToIP($ntpServer), 123)
If @error <> 0 Then Return SetError(1)

; $status = UDPSend($socket, MakePacket('1b0e010000000000000000004c4f434ccb1eea7b866665cb00000000000000000000000000000000cb1eea7b866665cb'))
Local $status = UDPSend($socket, MakePacket('1b0e01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'))
If $status = 0 Then Return SetError(1)

Local $data = '', $a = TimerInit() ; Timer setzen, damit im Fehlerfall die Schleife abgebrochen wird

While $data = ''
    $data = UDPRecv($socket, 100)
    Sleep(100)

    If TimerDiff($a) > 1000 Then ExitLoop ; Wenn Timer > 1sek. (Fehler), dann Schleife verlassen
WEnd

If $data <> '' Then
    UDPShutdown()

    Local $unsignedHexValue = StringMid($data, 83, 8) ; Extract time from packet. Disregards the fractional second.
    Local $value            = UnsignedHexToDec($unsignedHexValue)
    Local $TZinfo           = _Date_Time_GetTimeZoneInformation()
    Local $TZoffset         = -(UnsignedToLong($TZinfo[1]) + (UnsignedToLong($TZinfo[4])*($TZinfo[0]<2)) + (UnsignedToLong($TZinfo[7])*($TZinfo[0]=2)))
    Local $UTC              = _DateAdd('s', $value, '1900/01/01 00:00:00')

    Return _DateAdd('n', $TZoffset, $UTC)
EndIf

SetError(1)

Он отлично работает в течение нескольких секунд.Как видите, есть комментарий «Не учитывает доли секунды».Итак, я проверил, как работает пакет ntp, и он показывает, что у вас есть 32 бита для секунд, 32 бита для дробных секунд, а затем еще 64 бита с секундами и долями с синусоидом 1.1.1900.

В коде, который он использует 8символы из пакета (я понятия не имею, почему он начинается с 83), преобразуйте это из шестнадцатеричного в декабрь, и тогда у вас будет время.Итак, моя первая мысль получить миллисекунды, получить следующие 8 символов, преобразовать их, и у меня есть миллисекунды, но это не так.

Если я получу время четыре раза и позволю программеспать между этим, затем распечатать время с миллисекундами, я получаю такие вещи:

2019/02/14 14:29:56.987628606

2019/02/14 14:29:56.243...

2019/02/14 14:29:56.388...

2019/02/14 14:29:57.1107...

Это не может быть правильно.Так что есть некоторая ошибка в декодировании пакета времени. Кто-нибудь знает, как? Мне не нужен экстремум времени в точности как в миллисекундах, его достаточно в диапазоне 200 - 300 мс.

Редактировать: Хорошо, насколько я тестировалпроблема заключается в преобразовании дроби в миллисекунды.

Для всей информации, необходимой в комментариях, вот и полный код:

  Func _TimeSync()
      Local $ntpServer = 'pool.ntp.org'
      UDPStartup()
      Dim $socket = UDPOpen(TCPNameToIP($ntpServer), 123)
      If @error <> 0 Then Return SetError(1)
      ;$status = UDPSend($socket, MakePacket('1b0e010000000000000000004c4f434ccb1eea7b866665cb00000000000000000000000000000000cb1eea7b866665cb'))
      Local $status = UDPSend($socket, MakePacket('1b0e01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'))
      If $status = 0 Then Return SetError(1)
      Local $data = '', $a = TimerInit() ; Timer setzen, damit im Fehlerfall die Schleife abgebrochen wird
      While $data = ''
          $data = UDPRecv($socket, 100)
          sleep(100)
          If TimerDiff($a) > 1000 Then ExitLoop ; Wenn Timer > 1sek. (Fehler), dann Schleife verlassen
      WEnd
      If $data <> '' Then
          UDPShutdown()
          Local $unsignedHexValue = StringMid($data,83,8); Extract time from packet. Disregards the fractional second.
          Local $unsignedHexValue2 = StringMid($data,91,8); Extract time from packet. Disregards the fractional second.
          Local $value = UnsignedHexToDec($unsignedHexValue)
          Local $value2 = UnsignedHexToDec($unsignedHexValue2)
          Local $TZinfo = _Date_Time_GetTimeZoneInformation()
          Local $TZoffset = -(UnsignedToLong($TZinfo[1]) + (UnsignedToLong($TZinfo[4])*($TZinfo[0]<2)) + (UnsignedToLong($TZinfo[7])*($TZinfo[0]=2)))
          Local $UTC = _DateAdd('s',$value,'1900/01/01 00:00:00')
          Return _DateAdd('n',$TZoffset,$UTC)&"."&($value2)
      EndIf
      SetError(1)
   EndFunc

  Func MakePacket($d)
      Local $p = ''
      While $d
          $p &= Chr(Dec(StringLeft($d,2)))
          $d = StringTrimLeft($d,2)
      WEnd
      Return $p
   EndFunc

  Func UnsignedHexToDec($n)
      Local $ones = StringRight($n,1)
      $n = StringTrimRight($n,1)
      Return dec($n)*16+dec($ones)
   EndFunc


  Func UnsignedToLong($Value)
      Local Const $OFFSET_4 = 4294967296
      Local Const $MAXINT_4 = 2147483647
      If $Value < 0 Or $Value >= $OFFSET_4 Then Return SetError(1,0,$Value) ;' Overflow
      If $Value <= $MAXINT_4 Then
          Return $Value
      Else
          Return $Value - $OFFSET_4
      EndIf
   EndFunc

Я не мог понять, как преобразоватьдроби до нормальных значений типа int или float

...