【问题标题】:endians, languages, hardwares and network字节序、语言、硬件和网络
【发布时间】:2011-08-03 19:53:11
【问题描述】:

我们知道字节序与计算机存储数据的方式有关。大端计算机体系结构包括 IBM 370、摩托罗拉 68000 和 Sun Sparc。小端计算机包括英特尔系列(80486、奔腾等)和 VAX。

由于 JVM,Java 始终是 Big-Endian。 由于协议,网络应始终为 Big-Endian。

  1. C、C++ 和 C# 依赖于它们正在运行的计算机吗?
  2. 由于协议,网络应始终为 Big-Endian。如果我们在发送之前不调用 htons 和 htonl 怎么样?如果发送者是英特尔机器上的 C++,则发送的数据将是 Little-endian。对吗?
  3. 所以我们不需要关心字节序(调用 ntohl 和 htonl),如果我们知道所有客户端和服务器将使用具有相同架构的计算机并使用相同的程序语言。对吗?

【问题讨论】:

  • 您是否试图为编写不可移植代码提出论据,因为目前您拥有一组统一的机器。历史已经(很多次)表明,短视的优化尝试永远不会得到回报,因为预测未来是不可能的。您基本上是在尝试将工作推给代码维护者,当未来将他踢到牙齿时,他将不得不修复您损坏的不可移植代码。所以编码就好像他(维护者)知道你住在哪里并且拥有一把斧头。
  • 还有谁说网络层没有某种形式的内部压缩来很好地处理“网络字节顺序”中的数字。你过早的优化会搞砸的。

标签: c# java c++ networking programming-languages


【解决方案1】:
  1. 对于 C 和 C++,至少,是的;字节顺序通常取决于机器(但也可能取决于编译器)。对于 C#,我不知道。
  2. 很多网络协议都是大端的,是的。如果您不调用 htonl,那么您将不会在 little-endian 机器上创建有效的数据包。
  3. 因此,您应该始终致电htonl 等(或您使用的任何语言的等价物)。因为即使您今天拥有同质的环境,但几乎可以肯定,在未来,这种情况会发生变化。

更具体地说,您应该始终尽可能靠近界面在一个地方进行转换。如果您的代码库中散布着字节序转换调用,则很难推断您的代码是否合理。

【讨论】:

    【解决方案2】:
    1. 计算机之间以二进制形式传输的数据取决于 Endian 顺序。

    2. C、C++ 和 C# 不对 Endianess 提出任何要求或要求。

    3. 网络应遵循协议。根据协议输入和写出数字后,数字将转换为内部格式。它们可以是用于内部处理的任何格式。

    4. 在计算机之间传输二进制数据时只需担心字节顺序,无论是存储在文件中还是立即传输。

    5. 浮点数也存在类似问题。

    6. 许多语言不关心字节顺序。

    【讨论】:

      【解决方案3】:

      严格来说,Java 使用与运行它的硬件相同的字节序,但它不会向 JVM 用户显示,因为您无法访问 Java 中的原始内存。

      1. 没错,C 语言使用当前运行的处理器使用的布局。
      2. 正确。
      3. 无论如何,始终转换为网络字节顺序是一种很好的做法。迟早你会后悔你没有使用 htons(和其他)只是因为暂时它并不重要。费用通常很低,除非您有充分的理由不这样做,否则请这样做!

      【讨论】:

      • 如果你使用 JNI 之类的东西,我相信你可以访问原始内存。
      • @Oli - 是的,这是完全正确的!但是 JNI 是用 C/C++ 而不是 Java 编程的。我认为有一些方法(至少使用已弃用的 API:s)可以找出正在运行的机器的字节顺序 - 但实际上 Java 程序不应该关心是否正确编写。
      • 我想我的意思是 JNI 是 JVM 的字节序明确地暴露给用户的地方。
      【解决方案4】:

      在非常抽象的术语中,您必须了解字节序和特定于字节序的唯一一次是序列化数据。这有一个非常精确的含义,实际上在某种程度上被 C++ 中的语言标准所涵盖:

      在程序的主体部分,数据来自特定类型的变量,写为T x;。到目前为止如此便携;你的程序总是做你想做的事,你不需要知道x 在内部是如何表示的。你知道x 的内存从&x 开始,长度为sizeof(T) 字节,但你什么都不知道。如果您确实想知道,则必须将 &xT* 转换为 unsigned char*

      虽然一般禁止转换指针(称为“类型双关语”),但这种特殊的转换是标准明确允许的。转换为 char-pointer 是将数据从不透明类型 T序列化 转换为实际字节流的唯一方法。正是在这个时候,您必须了解字节顺序(或更一般地说,表示),因为您必须知道字节流以何种顺序构成T 的内部表示。

      对于整型可以不用转换指针,但是接口还在字节流到值的转换:

      unsigned char buf[sizeof(unsigned int)];
      unsigned int value;
      
      buf[0] = value; buf[1] = value >> 8; buf[2] = value >> 16; /*...*/  // We chose an endianness!
      value = buf[0] + (buf[1] << 8) + (buf[2] << 16) + ... ; // ditto
      

      在使用readwrite 等操作时,您会发现需要将值转换为字节流,反之亦然,这些操作通常与文件、流或套接字相关联。

      请注意,对于整数值,我们从不需要知道程序本身的字节序——我们需要知道字节流使用的字节序!

      【讨论】:

        猜你喜欢
        • 2014-05-18
        • 1970-01-01
        • 2022-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多