主機字節(jié)序與網絡字節(jié)序的轉換函數:htonl、ntohl惫皱、htons像樊、ntohs

Part 1: htons函數具體解釋

Linux和Windows網絡編程時需要用到htons和htonl函數,用來將主機字節(jié)順序轉換為網絡字節(jié)順序旅敷。

在Intel機器下生棍,執(zhí)行以下程序

int main()
{
      printf("%d /n",htons(16));
      return 0;
}

得到的結果是4096,初一看感覺很怪媳谁。

解釋如下:
數字16的16進制表示為0x0010涂滴,數字4096的16進制表示為0x1000。
由于Intel機器是小尾端晴音,存儲數字16時實際順序為1000柔纵,存儲4096時實際順序為0010。
因此在發(fā)送網絡包時為了報文中數據為0010锤躁,需要經過htons進行字節(jié)轉換搁料。
如果用IBM等大尾端機器,則沒有這種字節(jié)順序轉換系羞,但為了程序的可移植性郭计,也最好用這個函數。

另外用注意椒振,數字所占位數小于或等于一個字節(jié)(8 bits)時昭伸,不要用htons轉換。這是因為對于主機來說杠人,大小尾端的最小單位為字節(jié)(byte)勋乾。

Part 2: 大小端模式

不同的CPU有不同的字節(jié)序類型 這些字節(jié)序是指整數在內存中保存的順序 這個叫做主機序
最常見的有兩種:
1. Little endian:將低序字節(jié)存儲在起始地址
2. Big endian:將高序字節(jié)存儲在起始地址

LE little-endian

最符合人的思維的字節(jié)序
地址低位存儲值的低位
地址高位存儲值的高位
怎么講是最符合人的思維的字節(jié)序宋下,是因為從人的第一觀感來說
低位值小嗡善,就應該放在內存地址小的地方,也即內存地址低位
反之学歧,高位值就應該放在內存地址大的地方罩引,也即內存地址高位

BE big-endian

最直觀的字節(jié)序
地址低位存儲值的高位
地址高位存儲值的低位
為什么說直觀,不要考慮對應關系
只需要把內存地址從左到右按照由低到高的順序寫出
把值按照通常的高位到低位的順序寫出
兩者對照枝笨,一個字節(jié)一個字節(jié)的填充進去

例子:在內存中雙字0x01020304(DWORD)的存儲方式

內存地址
4000 4001 4002 4003
LE 04 03 02 01
BE 01 02 03 04

例子:如果我們將0x1234abcd寫入到以0x0000開始的內存中袁铐,則結果為
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x23 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
x86系列CPU都是little-endian的字節(jié)序.

網絡字節(jié)順序是TCP/IP中規(guī)定好的一種數據表示格式揭蜒,它與具體的CPU類型、操作系統(tǒng)等無關剔桨,從而可以保證數據在不同主機之間傳輸時能夠被正確解釋屉更。<u style="box-sizing: border-box; outline: 0px; margin: 0px; padding: 0px; word-wrap: break-word;">網絡字節(jié)順序采用big endian排序方式。</u>

為了進行轉換 bsd socket提供了轉換的函數 有下面四個
htons 把unsigned short類型從主機序轉換到網絡序
htonl 把unsigned long類型從主機序轉換到網絡序
ntohs 把unsigned short類型從網絡序轉換到主機序
ntohl 把unsigned long類型從網絡序轉換到主機序

在使用little endian的系統(tǒng)中 這些函數會把字節(jié)序進行轉換
在使用big endian類型的系統(tǒng)中 這些函數會定義成空宏

同樣 在網絡程序開發(fā)時 或是跨平臺開發(fā)時 也應該注意保證只用一種字節(jié)序 不然兩方的解釋不一樣就會產生bug.

注:
1洒缀、網絡與主機字節(jié)轉換函數:htons ntohs htonl ntohl (s 就是short l是long h是host n是network)
2瑰谜、不同的CPU上運行不同的操作系統(tǒng),字節(jié)序也是不同的树绩,參見下表萨脑。
處理器 操作系統(tǒng) 字節(jié)排序
Alpha 全部 Little endian
HP-PA NT Little endian
HP-PA UNIX Big endian
Intelx86 全部 Little endian <-----x86系統(tǒng)是小端字節(jié)序系統(tǒng)
Motorola680x() 全部 Big endian
MIPS NT Little endian
MIPS UNIX Big endian
PowerPC NT Little endian
PowerPC 非NT Big endian <-----PPC系統(tǒng)是大端字節(jié)序系統(tǒng)
RS/6000 UNIX Big endian
SPARC UNIX Big endian
IXP1200 ARM核心 全部 Little endian

Part 3: 模擬htonl、ntohl饺饭、htons渤早、ntohs函數實現


今天在如鵬網里討論htonl、ntohl在不同機器的區(qū)別瘫俊,特意模擬了htonl鹊杖、ntohl、htons扛芽、ntohs函數實現仅淑。
實現如下:
typedef unsigned short int uint16;

typedef unsigned long int uint32;

// 短整型大小端互換

define BigLittleSwap16(A) ((((uint16)(A) & 0xff00) >> 8) | /

                                             (((uint16)(A) & 0x00ff) << 8))

// 長整型大小端互換

define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) | /

                                             (((uint32)(A) & 0x00ff0000) >> 8) | /

                                             (((uint32)(A) & 0x0000ff00) << 8) | /

                                             (((uint32)(A) & 0x000000ff) << 24))

// 本機大端返回1,小端返回0

int checkCPUendian()

{

   union{

          unsigned long int i;

          unsigned char s[4];

   }c;

   c.i = 0x12345678;

   return (0x12 == c.s[0]);

}

// 模擬htonl函數胸哥,本機字節(jié)序轉網絡字節(jié)序

unsigned long int HtoNl(unsigned long int h)

{

   // 若本機為大端涯竟,與網絡字節(jié)序同,直接返回

   // 若本機為小端空厌,轉換成大端再返回

   return checkCPUendian() ? h : BigLittleSwap32(h);

}

// 模擬ntohl函數庐船,網絡字節(jié)序轉本機字節(jié)序

unsigned long int NtoHl(unsigned long int n)

{

   // 若本機為大端,與網絡字節(jié)序同嘲更,直接返回

   // 若本機為小端筐钟,網絡數據轉換成小端再返回

   return checkCPUendian() ? n : BigLittleSwap32(n);

}

// 模擬htons函數,本機字節(jié)序轉網絡字節(jié)序

unsigned short int HtoNs(unsigned short int h)

{

   // 若本機為大端赋朦,與網絡字節(jié)序同篓冲,直接返回

   // 若本機為小端,轉換成大端再返回

   return checkCPUendian() ? h : BigLittleSwap16(h);

}

// 模擬ntohs函數宠哄,網絡字節(jié)序轉本機字節(jié)序

unsigned short int NtoHs(unsigned short int n)

{

   // 若本機為大端壹将,與網絡字節(jié)序同,直接返回

   // 若本機為小端毛嫉,網絡數據轉換成小端再返回

   return checkCPUendian() ? n : BigLittleSwap16(n);

}
引自:https://blog.csdn.net/androidbbc/article/details/81980068

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末诽俯,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子承粤,更是在濱河造成了極大的恐慌暴区,老刑警劉巖闯团,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異仙粱,居然都是意外死亡房交,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門伐割,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涌萤,“玉大人,你說我怎么就攤上這事口猜「合” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵济炎,是天一觀的道長川抡。 經常有香客問我,道長须尚,這世上最難降的妖魔是什么崖堤? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮耐床,結果婚禮上密幔,老公的妹妹穿的比我還像新娘。我一直安慰自己撩轰,他們只是感情好胯甩,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堪嫂,像睡著了一般偎箫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皆串,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天淹办,我揣著相機與錄音,去河邊找鬼恶复。 笑死怜森,一個胖子當著我的面吹牛,可吹牛的內容都是我干的谤牡。 我是一名探鬼主播副硅,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拓哟!你這毒婦竟也來了想许?” 一聲冷哼從身側響起伶授,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤断序,失蹤者是張志新(化名)和其女友劉穎流纹,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體违诗,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡漱凝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了诸迟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茸炒。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖阵苇,靈堂內的尸體忽然破棺而出壁公,到底是詐尸還是另有隱情,我是刑警寧澤绅项,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布紊册,位于F島的核電站,受9級特大地震影響快耿,放射性物質發(fā)生泄漏囊陡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一掀亥、第九天 我趴在偏房一處隱蔽的房頂上張望撞反。 院中可真熱鬧,春花似錦搪花、人聲如沸遏片。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丁稀。三九已至,卻和暖如春倚聚,著一層夾襖步出監(jiān)牢的瞬間线衫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工惑折, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留授账,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓惨驶,卻偏偏與公主長得像白热,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子粗卜,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容