本文以及另外兩篇相關文章解釋 Windows Sockets 編程方面的一些問題。本文介紹字節排序。其他問題在文章 Windows Sockets:阻塞和 Windows Sockets:轉換字符串中介紹。
如果使用 CAsyncSocket 類或從其派生,則您需要自己管理這些問題。如果您使用 CSocket 類或從其派生,則由 MFC
管理它們。
不同的計算機結構有時使用不同的字節順序存儲數據。例如,基於 Intel 的計算機存儲數據的順序與 Macintosh
(Motorola) 計算機相反。Intel 字節順序稱為“Little-Endian”,與網絡標准“Big-Endian”順序也相反。下表解
釋這些術語。
Big-Endian 和 Little-Endian 字節排序
通常,您不必為在網絡上發送和接收的數據的字節順序轉換擔心,但在有些情況下,您必須轉換字節順序。
在下列情況中需要轉換字節順序:
必須為網絡理解。
排序,則需要字節順序轉換。
在下列情況下可以免去轉換字節順序的工作:
使用 CAsyncSocket 時,您必須自己管理任何必需的字節順序轉換。Windows Sockets 將“Big-Endian”字節順
序模型標准化,並提供在該順序和其他順序之間轉換的函數。然而,與 CSocket 一起使用的 CArchive 使用相
反的順序(“Little-Endian”),但 CArchive 為您管理字節順序轉換的細節。通過在應用程序中使用這種標准
排序,或通過使用 Windows Sockets 字節順序轉換函數,可增強代碼的可移植性。
最適合使用 MFC 套接字的情況是當編寫通信的兩端時:在兩端都使用 MFC。如果正在編寫將與非 MFC 應用程序
通信的應用程序(如 FTP 服務器),則在向存檔對象傳遞數據前,您可能需要使用 Windows Sockets 轉換例程
ntohs 、 ntohl 、 htons 和 htonl 自己管理字節交換。本文稍後將給出這些用於與非 MFC 應用程序通信的函數
示例。
注意 當通信的另一端不是 MFC 應用程序時,也必須避免將從 CObject 派生的 C++ 對象以流的形式輸入存
檔,因為接收端無法處理它們。請參見 Windows Sockets:使用帶存檔的套接字中的說明。
有關字節順序的更多信息,請參見 Platform SDK 中的 Windows Sockets 規范。
下面的示例顯示使用存檔的 CSocket 對象的一個序列化函數。它還闡釋了在 Windows Sockets API 中如何使用
字節順序轉換函數。
該示例顯示這樣的情形:您正在編寫與非 MFC 服務器應用程序通信的客戶程序,而您沒有訪問該服務器應用程序
源代碼的權限。在這種情況下,必須假設非 MFC 服務器使用標准的網絡字節順序。相反,MFC 客戶端應用程序對
CSocket 對象使用 CArchive 對象,而 CArchive 使用與網絡標准相反的“Little-Endian”字節順序。
假設要與之通信的非 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 服務器應用程序的字節排序與另一端在 MFC 客戶端應用程序中使用的 CArchive 明顯不匹配。該示例闡釋了 Windows Sockets 提供的幾個字節順序轉換函數。下表描述了這些函數。
Windows Sockets 字節順序轉換函數
此示例的另一個要點是,當通信另一端的套接字應用程序為非 MFC 應用程序時,必須避免出現如下列語句的操作:
ar pMsg;
這裡的 pMsg
是指向從 CObject 類派生的 C++ 對象的指針。這將發送多余的與對象關聯的 MFC 信息,而服務器並不理解這些信息,因為只有服務器是 MFC 應用程序時才理解。