【问题标题】:Why do I receive a different int then I've sent from using indy?为什么我收到的 int 与我使用 indy 发送的不同?
【发布时间】:2015-04-20 10:54:21
【问题描述】:

我检查过,当我将整数转换为十六进制时,它们分别变为 4C52 en 524C000000000000,所以看起来字节好像是颠倒的。

客户端在 Delphi XE7 for android 上运行,服务器在 Delphi 2007 上运行。

我该如何解决这个问题?

客户端推送码:Client.IOHandler.Write(19538);

服务器拉码:AContext.Connection.IOHandler.ReadInt64; //receives 5930114809340100608

【问题讨论】:

    标签: delphi indy delphi-2007 delphi-xe7


    【解决方案1】:

    您没有考虑字节序或字节大小。

    TIdIOHandler.Write() 的整数重载接受 主机字节顺序 的数值,根据平台的不同,它可能是小端或大端,并将它们转换为传输到 网络字节序,默认为大端。整数TIdIOHandler.Read...() 方法默认数值以网络字节顺序 到达,并且默认将它们转换为主机按顺序。所以,如果你在两边都使用 Indy,你不必担心这个细节,因为无论两端是哪个平台,读/写的字节序都是一致的。

    TIdIOHandler.Write() 数字重载和 TIdIOHandler.Read...() 数字方法都有一个可选的 Convert 参数,默认情况下为 True。如果您将此设置为 False,则将按 主机字节顺序 而不是 网络字节顺序 发送/读取值。

    更重要的是您正在阅读Int64,但您没有发送Int64。对于各种整数类型,TIdIOHandler.Write() 有多个重载,并且在存在此类重载的情况下,无类型的 19538 常量永远不会解析为 Int64。所以你需要使用类型转换来告诉编译器使用Int64重载:

    Client.IOHandler.Write(Int64(19538)); 
    

    或者使用变量:

    var
      Value: Int64;
    
    Value := 19538; 
    Client.IOHandler.Write(Value); 
    

    服务器拉取代码:AContext.Connection.IOHandler.ReadInt64; //收到5930114809340100608

    十六进制的 19538 是 0x4C52

    5930114809340100608 十六进制是0x524C000000000000

    注意到相似之处了吗?

    网络字节顺序中的 19538 是 4C 52 作为 16 位整数,00 00 4C 52 作为 32 位整数。那只有 2-4 个字节,但 Int64 是 8 个字节,所以必须有另外 4-6 个字节,否则 ReadInt64 不会返回。但是让我们假设存在额外的00 字节(在这种情况下,您没有正确处理协议数据)。为了让ReadInt64 从网络字节顺序中的 8 个字节返回 5930114809340100608,它必须接收到 52 4C 00 00 00 00 00 00,这与 19538 不接近匹配为网络字节顺序中的 16 位或 32 位整数。

    【讨论】:

      【解决方案2】:

      我已经用http://codeverge.com/embarcadero.delphi.basm/fastest-best-way-to-reverse-byte-orde/1096017的代码修复了它

      这是一个使用汇编的交换函数,所以现在我的代码如下:Swap8(AContext.Connection.IOHandler.ReadInt64);

      Swap8 函数是:

      function Swap8 (i: Int64): Int64;  register;
      asm
        mov eax, dword [i]
        bswap eax
        mov dword [Result+4], eax
        mov eax, dword [i+4]
        bswap eax
        mov dword [Result], eax
      end;
      

      【讨论】:

      • 您不需要单独的交换功能。数字 TIdIOHandler.Write()TIdIOHandler.Read...() 方法具有可选的 Convert 参数,用于处理字节交换。
      • 这绝对是错误的解决方案。使用主机到网络和网络到主机的概念。永远不要在高级代码中显式交换字节。
      猜你喜欢
      • 2020-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-07
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 1970-01-01
      相关资源
      最近更新 更多