Windows 套接字:字节排序

本文和两篇配套文章介绍了 Windows 套接字编程中的若干问题。 本文介绍了字节排序。 以下文章介绍了其他问题: Windows 套接字:阻止Windows 套接字:转换字符串

如果使用类 CAsyncSocket或从类派生,则需自行管理这些问题。 如果使用类 CSocket或从类派生,则 MFC 会为你进行管理。

字节排序

不同的计算机体系结构有时使用不同的字节顺序存储数据。 例如,基于 Intel 的计算机以 Macintosh (Motorola) 机的相反顺序存储数据。 Intel 字节顺序称为 "小字节序",也是网络标准 "大字节序" 顺序的反向。 下表说明了这些术语。

大和 Little-Endian 字节排序

字节排序 含义
Big-Endian 最重要的字节位于单词的左侧。
Little-Endian 最重要的字节位于单词的右端。

通常,您不必担心通过网络发送和接收的数据的字节顺序转换,但在某些情况下,必须转换字节顺序。

必须转换字节顺序

需要在以下情况下转换字节顺序:

  • 要传递需要由网络解释的信息,而不是发送到另一台计算机的数据。 例如,你可能会传递网络必须理解的端口和地址。

  • 要与之通信的服务器应用程序不是 (的 MFC 应用程序,并且你没有) 的源代码。 如果两台计算机不共享相同的字节顺序,则这将调用字节顺序转换。

不需要转换字节顺序时

在以下情况下,你可以避免转换字节顺序:

  • 两端的计算机都可以同意不交换字节,并且两台计算机使用相同的字节顺序。

  • 要与之通信的服务器是 MFC 应用程序。

  • 你具有要与之通信的服务器的源代码,因此你可以明确地判断是否必须转换字节顺序。

  • 您可以将服务器移植到 MFC。 这相当简单,而且结果通常更小,代码更快。

使用 CAsyncSocket时,必须自行管理任何所需的字节顺序转换。 Windows套接字对 "大字节序" 字节顺序模型进行标准化,并提供在此顺序和其他顺序之间进行转换的函数。 然而, CArchive用于CSocket,它使用相反 ( "小字节序" ) 顺序,但 CArchive 会为你处理字节顺序转换的详细信息。 通过在应用程序中使用此标准排序,或者使用 Windows 套接字字节顺序转换函数,可以使代码更易于移植。

使用 MFC 套接字的理想情况是在同时编写通信的两端:在两端使用 MFC。 如果你正在编写将与非 MFC 应用程序(如 FTP 服务器)进行通信的应用程序,则在将数据传递到 archive 对象之前,你可能需要管理自己的 byte 交换,并使用 Windows 套接字转换例程 ntohsntohlhtonshtonl。 本文稍后将显示与非 MFC 应用程序通信时所用的这些功能的示例。

备注

如果通信的另一端不是 MFC 应用程序,则还必须避免将派生自的 c + + 对象流式 CObject 处理到存档中,因为接收方将无法处理它们。 请参阅Windows 套接字:对存档使用套接字)中的说明。

有关字节顺序的详细信息,请参阅 Windows SDK 中提供的 Windows 套接字规范。

Byte-Order 转换示例

下面的示例演示使用存档的对象的序列化函数 CSocket 。 它还说明了如何使用 Windows 套接字 API 中的字节顺序转换函数。

此示例展示了这样一种情况:您正在编写一个客户端,该客户端与您无权访问源代码的非 MFC 服务器应用程序进行通信。 在此方案中,您必须假定非 MFC 服务器使用标准网络字节顺序。 与此相反,MFC 客户端应用程序将 CArchive 对象与 CSocket 对象结合使用,并 CArchive 使用 "小字节序" 字节顺序(与网络标准相反)。

假设你计划与之通信的非 MFC 服务器的消息包具有已建立的协议,如下所示:

struct Message
{
   long MagicNumber;
   unsigned short Command;
   short Param1;
   long Param2;
};

在 MFC 术语中,这会表达如下:

struct Message
{
   long m_lMagicNumber;
   short m_nCommand;
   short m_nParam1;
   long m_lParam2;

   void Serialize(CArchive &ar);
};

在 c + + 中,与 struct 类本质上是相同的。 Message结构可以具有成员函数,如 Serialize 上面声明的成员函数。 该 Serialize 成员函数可能如下所示:

void Message::Serialize(CArchive &ar)
{
   if (ar.IsStoring())
   {
      ar << (DWORD)htonl(m_lMagicNumber);
      ar << (WORD)htons(m_nCommand);
      ar << (WORD)htons(m_nParam1);
      ar << (DWORD)htonl(m_lParam2);
   }
   else
   {
      WORD w;
      DWORD dw;
      ar >> dw;
      m_lMagicNumber = ntohl((long)dw);
      ar >> w;
      m_nCommand = ntohs((short)w);
      ar >> w;
      m_nParam1 = ntohs((short)w);
      ar >> dw;
      m_lParam2 = ntohl((long)dw);
   }
}

此示例将对数据进行字节顺序转换,因为一端的非 MFC 服务器应用程序的字节排序与 CArchive 另一端上的 mfc 客户端应用程序中使用的字节顺序不匹配。 该示例演示了若干 Windows 套接字提供的字节顺序转换函数。 下表介绍了这些函数。

Windows套接字 Byte-Order 转换函数

函数 用途
ntohs 将16位数量从网络字节顺序转换为主机字节顺序 (大字节序转换为小字节序) 。
ntohl 将32位的数量从网络字节顺序转换为主机字节顺序 (大字节序转换为小字节序) 。
Htons 将16位数量从主机字节顺序转换为网络字节顺序, (小字节序转换为大字节序) 。
Htonl 将32位的数量从主机字节顺序转换为网络字节顺序 (小字节序转换为大字节序) 。

此示例的另一点是,当通信的另一端上的套接字应用程序是非 MFC 应用程序时,必须避免执行如下所示的操作:

ar << pMsg;

其中 pMsg ,是指向派生自类的 c + + 对象的指针 CObject 。 这将发送与对象关联的额外 MFC 信息,服务器将不会对其进行了解,这与它是 MFC 应用程序时一样。

有关详情,请参阅:

请参阅

MFC 中的 Windows 套接字