目前我试图从NTP服务器解码数据包。我正在自动尝试,这是一种简单的脚本语言。
我找到了一些代码,但问题是,我也需要毫秒。该代码仅提供秒。
那是我发现的代码:
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位SECS和SINTIONS SINE SINE SINE 1.1.1900。
。在代码中,他使用了数据包中的8个字符(我不知道他是为何从83开始),将其从十六进制转换为DEC,然后您有时间。因此,我第一次想到获得毫秒的是,得到接下来的8个字符,将其转换,我有Milli Secs,但不是。
。如果我获得了四次的时间,然后让程序中睡觉,然后用毫秒打印出时间,我会得到类似的东西:
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
分数秒钟以1/(2 ** numberofbits)秒为单位= 0.0000000000000232831,其中numberOfbits为4个字节*8位/字节/字节= 32位。因此,微秒的数量(6个小数位数)为:milliSecs = $ value2 * 0.000232830643654。但是显示超过3位数字可能意味着比真实更准确。