主機字節序和網絡字節序
在使用網絡進行程序設計中會碰到的一個問題是字節序的問題,這在基於單機或者同 類型機器進行開發的過程中很少遇到。由於網絡的特點是將 Internet 上不同的網絡設備和 主機進行連接和通信,這決定了使用網絡進行開發的程序的特點就是要兼容各種類型的設備,其中的數據在不同的設備上要有唯一的含義。字節序的問題是上述情況下的典型問題。
1. 字節序的含義
字節序的問題是由於 CPU 對整數在內存中的存放方式造成的。多於一個字節的數據類型在內存中的存放順序叫主機字節序。最常見的字節序有兩種,小端字節序和大端字節序。
█ 小端字節序:即 Little Endian,簡稱 LE,將數據的最低字節放在內存的起始位置。小端字節序的特點是內存地址較低的位存放數據的低位,內存地址髙的位存放數據的高位,與思維習慣一致。採用低字節序的 CPU 有 x86 架構的 Intel 系列產品。
█ 大端字節序:即 Big Endian,簡稱 BE,將數據的高字節放在內存的起始位置。大端字節序的特點是內存中低字節位置存放數據的高位字節,內存中的高位字節存放數據的較低字節數據,與思維習慣不一致。但是與實際數據的表達方式是一致的。如果將內存中的數據直接存放在文件中,打開文件查看會發現和原來的數據的高低位一致。採用大端字節序的典型的代表有 PowerPC 的 UNIX 系統。
例如,對於一個 8 位字節的數據 0x12345678,假設在內存中存放的開始地址爲 0x1000,則在小端字節序系統和大端字節序系統中的方式如下表(數據在小端字節序和大端字節序系統中的差別)所示。
內存地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
---|---|---|---|---|
小端字節序 | 0x78 | 0x56 | 0x34 | 0x12 |
大端字節序 | 0x12 | 0x34 | 0x56 | 0x78 |
而如果將 0x12345678 寫入內存地址 0x1000 開始的地方,在內存中的值爲下表(數據在小端字節序和大端字節序系統中的差別)所示的形式。
內存地址 | 小端字節序 | 大端字節序 |
---|---|---|
0x1000 | 0x12 | 0x78 |
0x1001 | 0x34 | 0x56 |
0x1002 | 0x56 | 0x34 |
0x1003 | 0x78 | 0x12 |
系統對多字節數據的不同存放方法造成了使用方法的問題,例如,在 x86 系統主機 A 上的一個值爲 0x12345678,數據通過網絡傳送到 PowerPC上的一個運行 UNIX 的主機 B 上,在 B 上此值解釋爲 0x78563412,與原來的數據迥異,這樣就造成了傳輸上兼容性方面的困難。
2. 網絡字節序的轉換
網絡的字節序標準規定爲大端字節序,不同平臺上會對主機字節序進行轉化後再進行傳送,到主機後再轉化爲主機字節序,數據的傳輸就不會產生傳輸造成的問題了。同一個數據在不同的平臺上可以使用網絡字節序的轉換函數來實現。
如下圖(不進行網絡字節序轉換的傳遞數據)所示爲主機 A 中的應用程序將變量 a 中的值 0x12345678,通過網絡傳遞給主機 B 中的應用程序中的變量 b,如果不進行網絡字節序轉換,b 的值爲 0x78563412。
如下圖(通過網絡字節序轉換在網絡間傳遞數據)所示,如果進行網絡字節序轉換,a 的值與 b 的值均爲 0x12345678。
進行網絡字節序轉換的函數有 htons()、ntohs()、htonl()、ntohl() 等,其中 s 是 short 數據類型的意思,l 是 long 數據類型的意思,而 h 是 host,即主機的意思,n 是 network,即網絡的意思。以上 4 個函數分別如下。
█ htons():表示對於 short 類型的變量,從主機字節序轉換爲網絡字節序。
█ ntohs():表示對於 short 類型的變量,從網絡字節序轉換爲主機字節序。
█ htonl():表示對於 long 類型的變量,從主機字節序轉換爲網絡字節序。
█ ntohl():表示對於 long 類型的變量,從網絡字節序轉換爲主機字節序。
字節序的轉換函數並沒有轉換符號類型變量,是否爲符號類型是由應用程式來確定的,與字節序無關。
字節序轉換函數在不同平臺上的實現是不同的,如對於 long 類型的轉換,小端主機字節序的平臺要進行轉換,而在大端主機字節序的平臺上是不需要進行轉換的。例如下面的實現方式可以兼容不同的平臺:
#if ISLE
/* 小端字節序平臺調用此部分代碼 */
long htonl(long value)
{
/* 進行轉換,即位置 0x12345678 轉換位置 → 0x78563412 */
return((value << 24)|((value << 8)&0x00FF0000)|((value >> 8)&0x0000FF00)|(value >> 24));
}
#else if ISBE
/* 大端字節序平臺調用此部分代碼 */
long htonl(long value)
{
/* 由於大端字節序平臺與網絡字節序一致,不需要進行轉換 */
return value;
}
#endif
不同的平臺的實現代碼是不同的部分。其他函數的實現與此類似,注意 htons() 和 ntohs() 函數及 htonl() 和 ntohl() 函數是對應的轉換,兩個函數完全可以使用同一套代碼,例如:
#define ntohl htonl
小結
ISO/OSI 網絡模型是進行網絡研究的基礎,該模型對各層之間的功能進行了抽象,仔細地研究此模型會對網絡協議棧的本質有更深入的瞭解。TCP 和 UDP 協議是應用程序設計中最常使用的兩種協議。TCP 是可靠的協議,用很多機制來保證數據傳輸的可靠性。UDP 則是一種不可靠的協議,在實際使用過程中,發送端的數據如果在接收端沒有及時地從協議棧緩衝區取出,有可能被之後到達的數據沖掉。
ICMP 是網絡控制協議,用於發送網絡的診斷、錯誤、控制信息。ARP 則是地址解析協議,獲得 IP 地址對應的硬件地址;與 RARP 協議如 ARP 相反的協議,叫逆地址解析協議,獲得硬件地址對應的 IP 地址,通常用於無盤工作站。
IP 地址是一種點分四段式的數據,表示一個主機在 Internet 上的網絡位置,主要用於跨網主機的識別。掩碼用於快速尋址和網絡劃分。