【问题标题】:Ntp packet decodentp数据包解码
【发布时间】:2021-08-16 12:23:04
【问题描述】:

目前我正在尝试解码来自 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 毫秒的范围内就足够了。

编辑: 好的,据我测试,问题在于将分数转换为毫秒。

对于 cmets 中想要的所有信息,这就是完整的代码:

  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

【问题讨论】:

  • 请提供更多关于您不完整的功能/代码的信息。以下函数的外观如何:MakePacket()UnsignedHexToDec()UnsignedToLong()?还请添加您使用的包含脚本#include &lt;???.au3&gt;
  • 你的脚本是否引用了post of user Rex at autoitscript
  • 你是如何像你写的那样用毫秒打印出时间的?
  • 如以下讨论所述,不应该有获得毫秒的方法:StackOverflow

标签: autoit ntp


【解决方案1】:

小数秒的测量单位为 1/(2**numberOfBits) 秒 = 0.000000000232831,其中 numberOfBits 为 4 字节 * 8 位/字节 = 32 位。所以微秒数(6个十进制数字)例如是:milliSecs = $value2 * 0.000232830643654。但显示超过 3 位数字可能意味着比实际情况更准确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-18
    相关资源
    最近更新 更多