本文和兩篇隨附文章說明 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 轉換例程 ntohs、 ntohl、 htons 和 htonl。 本文稍後會出現用於與非 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 應用程式一樣。
如需詳細資訊,請參閱: