共用方式為


Windows 套接字:位元組排序

本文和兩篇隨附文章說明 Windows Sockets 程式設計中的幾個問題。 本文涵蓋位元組排序。 文章涵蓋其他問題: Windows 套接字:封鎖Windows 套接字:轉換字串

如果您使用或衍生自 CAsyncSocket 類別,您必須自行管理這些問題。 如果您使用或衍生自 類別 CSocket,MFC 會為您管理它們。

位元組序

不同的計算機架構有時會使用不同的位元組順序來儲存數據。 例如,以 Intel 為基礎的機器會以 Macintosh(Motorola) 機器的反向順序儲存數據。 Intel 位元組順序,稱為「小端序」,也是網路標準的「大端序」順序的反向。 下表說明這些詞彙。

大端和Little-Endian位元排序

位元組排序 意義
Big-Endian 最重要的位元組位於單字的左端。
Little-Endian 最重要的位元組是在字的右邊。

通常,您不需要擔心透過網路傳送和接收的數據位元組順序轉換,但在某些情況下,您必須轉換位元組訂單。

當您必須轉換字節順序時

您需要在下列情況下轉換位元組訂單:

  • 您傳遞的資訊需要由網路解譯,而不是傳送至另一部計算機的數據。 例如,您可以傳遞網路必須瞭解的埠和位址。

  • 您正在通訊的伺服器應用程式不是 MFC 應用程式(而且您沒有原始程式碼)。 如果兩部計算機未共用相同的位元組順序,這會呼叫位元組順序轉換。

當您不需要轉換位元組順序時

在下列情況下,您可以避免轉換位元組順序的工作:

  • 兩端的機器都同意不交換位元組,而且兩部機器都使用相同的位元組順序。

  • 您與之通訊的伺服器是 MFC 應用程式。

  • 您擁有與伺服器通訊的原始程式碼,因此您可以明確判斷是否必須轉換位元組序列。

  • 您可以將伺服器移植到 MFC。 這相當容易執行,而且結果通常較小、更快速的程序代碼。

使用 CAsyncSocket 時,您必須自行管理任何必要的位元組順序轉換。 Windows Sockets 會將「big-Endian」位元組順序模型標準化,並提供函式來轉換此順序與其他函式。 不過,您搭配 CSocket 使用的 CArchive 會使用相反的 (“little-Endian”) 順序,但CArchive會為您處理位元組順序轉換的詳細數據。 藉由在應用程式中使用此標準排序,或使用 Windows Sockets 位元組順序轉換函式,您可以讓程式代碼更具可移植性。

理想的情況是使用 MFC 套接字來撰寫通訊的兩端,即在兩端都使用 MFC。 如果您要撰寫與非 MFC 應用程式通訊的應用程式,例如 FTP 伺服器,您可能需要先自行管理位元組交換,才能將數據傳遞至封存物件,使用 Windows Sockets 轉換例程 ntohsntohlhtonshtonl。 本文稍後會出現用於與非 MFC 應用程式通訊的這些函式範例。

備註

當通訊的另一端不是 MFC 應用程式時,您也必須避免串流C++衍生自 CObject 封存的物件,因為接收者無法處理它們。 請參閱 Windows 套接字:搭配封存使用套接字中的附註。

如需位元組訂單的詳細資訊,請參閱 Windows SDK 中提供的 Windows 套接字規格。

Byte-Order 轉換範例

下列範例顯示如何使用存檔對 CSocket 物件進行串行化函式處理。 它也說明如何在 Windows Sockets API 中使用位元組順序轉換函式。

此範例會示範您撰寫用戶端來與無法存取原始程式碼的非 MFC 伺服器應用程式通訊的案例。 在此案例中,您必須假設非 MFC 伺服器使用標準網路位元組順序。 相反地,您的 MFC 用戶端應用程式會使用 CArchive 物件搭配 CSocket 物件,並使用與網路標準相反的「小端序」位元排列順序。

假設您計劃通訊的非 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 Sockets 提供的數位元組順序轉換函式。 下表描述這些函式。

Windows Sockets Byte-Order 轉換函式

功能 目標
ntohs 將 16 位元數據從網路位元組順序轉換為主機位元組順序(由大端到小端)。
ntohl 將 32 位值從網路位元組順序轉換為主機位元組順序(big-Endian 到 little-Endian)。
Htons 將16位數量從主機位元組順序轉換為網路位元組順序(小端到大端)。
Htonl 將 32 位數量從主機字節順序轉換為網路字節順序(小端序到大端序)。

此範例的另一個要點是,當通訊的另一端套接字應用程式是非 MFC 應用程式時,您必須避免執行類似下列動作:

ar << pMsg;

其中 pMsg 是衍生自 類別 CObject之C++物件的指標。 這會傳送與對象相關聯的額外 MFC 資訊,而且伺服器不會瞭解它,就如同它是 MFC 應用程式一樣。

如需詳細資訊,請參閱:

另請參閱

MFC 中的 Windows 套接字