首页 > 解决方案 > 使用 BytesToInt64() 将 TIdBytes 转换为 Integer 的意外结果

问题描述

我正在使用该TIdUDPServer.OnUDPRead事件读取 UDP 数据包。每个数据包中嵌入了一个 8 字节QUint64的 ,代表一个无线电频率。我正在尝试读取该频率。

所有尝试使用BytesToInt64()都会导致错误的结果。我已经通过使用 Wireshark 读取十六进制值并使用基于 Web 的十六进制到十进制转换器来验证数据是否正确。

我知道数据包数据中的频率从位置 23 开始,长度为 8 个字节。

procedure TWSJTxUDPClient.IdUDPServer1UDPRead(AThread:  TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  FreqInt: Int64;

begin
  FreqInt := BytesToInt64(AData,23);
  LabelFreq.Caption := IntToStr(FreqInt);
end;

这是电线上以十六进制表示的数据,从位置 23 开始:

00 00 00 00 00 6b f0 d0

它代表 7074000 赫兹的频率。

我上面的代码导致频率值为 58811137507983360。

我还通过使用Ord()表示频率的字符串上的函数读取每个字节来确认十六进制数据。

FreqStr := BytesToString(Adata,23,8);
Int8 := Ord(FreqStr[8]);

Int8 现在 = 208 - 0xd0 的正确值。对字节 5、6 和 7 执行相同操作。确认。

所以我知道我缺少一些基本的东西。

标签: indydelphi-10.1-berlin

解决方案


您没有考虑字节序。

十进制7074000是十六进制0x6BF0D0。十进制58811137507983360是十六进制0xD0F06B00000000。看到相似之处了吗?它们的字节顺序相反。

数据包中的字节按网络字节顺序(大端),但您的机器使用小端。您需要交换Int64. 您可以为此使用 Indy 的GStack.NetworkToHost()方法:

procedure TWSJTxUDPClient.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  FreqInt: Int64;
begin
  FreqInt := BytesToInt64(AData, 23);
  FreqInt := Int64(GStack.NetworkToHost(UInt64(FreqInt)));
  LabelFreq.Caption := IntToStr(FreqInt);
end;

推荐阅读