【问题标题】:C/C++ Endianness and tcp socketsC/C++ 字节序和 tcp 套接字
【发布时间】:2014-04-17 11:41:44
【问题描述】:

我有一个关于字节序的一般概念问题,以及它如何影响与 C/C++ 的 tcp 套接字通信。这是一个例子:

您有两台服务器正在与 tcp 套接字通信,一台使用大端,另一台使用小端。如果您通过套接字从一台服务器向另一台服务器发送一个整数,我知道字节顺序是相反的,并且整数不会打印预期的内容。正确的?我在某处看到(我再也找不到哪里了),如果你通过套接字字节序发送一个字符并不会改变值,它会按预期打印。它是否正确?如果是这样,为什么?我觉得我过去曾这样做过,但我可能会产生妄想。

谁能帮我解决这个问题?

谢谢。

编辑:是不是因为 char 只有 1 个字节?

【问题讨论】:

    标签: c++ c sockets endianness


    【解决方案1】:

    考虑每种数据类型的大小。

    一个整数通常是四个字节,您可以将其视为并排的四个单独的字节。体系结构的字节顺序决定了最高有效字节是四个字节中的第一个,还是最后一个。然而,一个字符只有一个字节。据我了解,字节序不会影响每个字节中位的顺序(参见Wikipedia 字节序页面上的图像)。

    然而,一个字符只有一个字节,所以没有替代顺序(假设我是正确的,位不被字节序修改)。

    如果你通过套接字发送一个字符,它在两台机器上都是一个字节。如果您通过套接字发送一个 int,因为它是四个字节,根据字节序,一台机器可能会以与另一台不同的顺序解释字节。您应该设置一个简单的方法来测试它并返回一些结果!

    【讨论】:

    • 谢谢。这正是我在进行上述编辑时的想法。
    • 我希望我可以添加更多具体信息,但我不确定套接字如何处理字节序,如果他们这样做的话。
    • 我确定整数会搞砸,但我一直在使用字符并将它们转换为整数。我班上的人认为我在执行一些巫术而不是手动反转字节。
    • 可行,但处理大于 255 的数字会很麻烦。我能想到的一个简单解决方案是让一台机器将 int 设置为 1,然后将其发送到其他。如果 int 被解释为 1(相同的字节序),则另一个可以用设置为 1 的字节响应,否则为零。
    • 典型的解决方案是使用函数htonntoh。也就是说,转换为网络字节序,然后再转换回另一端。如果你总是对多字节类型这样做,你应该没问题。
    【解决方案2】:

    字节字节序是指大于1字节的数据类型(如short、int、long等)中各个字节的顺序

    所以你的假设对于int 是正确的(因为它必须至少为 16 位,现在通常更多)。 char 通常也是正确的,因为它们通常是 1 个字节。但是你可能有超过 8 位的字符,在这种情况下字节序很重要。

    【讨论】:

    • 多字节字符编码(例如 UTF-8)将单个字符编码为字节序列,但这些字节仍然是独立编码的。
    • UTF-8 可能就是这种情况,但问题仍然存在于其他类型的编码,例如 UTF-16(请参阅en.wikipedia.org/wiki/UTF-16#Byte_order_encoding_schemes
    • @SleuthEye UTF-16 是唯一一种涉及大于一个字节的字的可变长度编码。 “多字节”只是通过与其他编码类比而应用于它。 UCS-16(仅限于 BMP)和 UCS-32 不是“多字节”。您暗示了多字节和字节序之间不存在的关系。
    【解决方案3】:

    您可以通过 TCP 套接字发送的唯一内容是字节。如果不首先为该整数创建一些字节表示,就不能通过 TCP 套接字发送整数。 C/C++ 类型integer 可以以平台喜欢的任何方式存储在内存中。如果这恰好是您需要通过 TCP 套接字发送它的形式,那么很好。但如果不是,那么您必须在发送前转换为协议要求的格式,并在收到后转换为您的本机格式。

    作为一个草率的类比,考虑一下我与您交流的方式。我的母语可能是西班牙语,谁知道我脑子里在想什么。在内部,我可能将数字 3 表示为“tres”或某种奇怪的神经元模式。谁知道?但是当我与你交流时,我必须将数字三表示为“3”或“三”,因为这是你我同意的协议,即英语。因此,除非我的英语说得不好,否则我在内部存储数字 3 的方式不会影响我与您的交流。

    由于这个小组需要我生成英文字符流与你交谈,我必须将我的内部数字表示转换为英文字符流。除非我在这方面做得很糟糕,否则我在内部存储数字的方式不会影响我生成的英文字符流。

    所以除非你做傻事,否则这无关紧要。由于您将通过 TCP 套接字发送和接收字节,integer 类型的内存格式无关紧要,因为您不会发送或接收 C/C++ integer 类型的实例,而是逻辑整数。

    例如,如果您通过 TCP 发送的数据的协议规范规定您需要以 little-endian 格式发送一个四字节整数,那么您应该编写代码来执行此操作。如果代码考虑了您平台的字节序,那将纯粹是一种优化,不应影响代码行为。

    【讨论】:

      【解决方案4】:

      您有两台服务器正在与 tcp 套接字进行通信,其中一台 使用大端和另一个小端。如果你发送一个整数, 通过套接字,从一台服务器到另一台服务器,我知道 字节顺序颠倒了,整数不会打印什么是 预计。

      这是网络通信协议中一个众所周知的问题。正确的答案是不发送任何整数。

      您定义的协议非常指定包含,例如以大端顺序存储的 32 位有符号整数。 Big-endian 恰好是网络协议中最常用的。

      在您要使用的计算机中,说签名长。 C 标准将 unsigned long 定义为具有 minimum 范围。实际存储可能有很大不同。它至少是 32 位,但可能更多。

      在您编译代码的平台上,会有宏允许您在网络中的“内部”整数和网络 32 位有符号大端序之间进行转换。例如 htonl() 和 ntohl()。这些宏将根据您所编译的平台变成不同的代码。

      【讨论】:

        【解决方案5】:

        只要您只传输字节就没有关系。而且您应该只在标准网络中传输字节。strong text

        【讨论】:

        • 考虑添加更详细的答案。如果您没有,请考虑发表评论。
        猜你喜欢
        • 2018-04-03
        • 2015-12-14
        • 1970-01-01
        • 1970-01-01
        • 2020-04-29
        • 1970-01-01
        • 1970-01-01
        • 2017-11-01
        • 1970-01-01
        相关资源
        最近更新 更多