socket 大端 小端 轉換

原文鏈接

不同機器內部對變量的字節存儲順序不同,有的採用大端模式(big-endian),有的採用小端模式(little-endian)。
大端模式是指高字節數據存放在低地址處,低字節數據放在高地址處。
小端模式是指低字節數據存放在低地址處,高字節數據放在高地址處。

在網絡上傳輸數據時,由於數據傳輸的兩端可能對應不同的硬件平臺,採用的存儲字節順序也可能不一致,因此 TCP/IP 協議規定了在網絡上必須採用網絡字節順序(也就是大端模式) 。
通過對大小端的存儲原理分析可發現,對於 char 型數據,由於其只佔一個字節,所以不存在這個問題,這也是一般情況下把數據緩衝區定義成 char 類型 的原因之一。對於 IP 地址、端口號等非 char 型數據,必須在數據發送到網絡上之前將其轉換成大端模式,在接收到數據之後再將其轉換成符合接收端主機的存儲模式。

Linux 系統爲大小端模式的轉換提供了 4 個函數,輸入 man byteorder 命令可得函數原型:

點擊(此處)摺疊或打開

  1. <EM><STRONG><SPAN>#include <arpa/inet.h>

  2. uint32_t htonl(uint32_t hostlong);

  3. uint16_t htons(uint16_t hostshort);

  4. uint32_t ntohl(uint32_t netlong);

  5. uint16_t ntohs(uint16_t netshort);</SPAN>
  6. </STRONG>
  7. </EM>
htonl 表示 host to network long ,用於將主機 unsigned int 型數據轉換成網絡字節順序;
htons 表示 host to network short ,用於將主機 unsigned short 型數據轉換成網絡字節順序;
ntohl、ntohs 的功能分別與 htonl、htons 相反。
 
通常使用的有兩種數據類型:短型(兩個字節)和長型(四個字節)。

    下面介紹的這些轉換函數對於這兩類的無符號整型變量都可以正確的轉換。 

    如果你想將一個短型數據從主機字節順序轉換到網絡字節順序的話,有這樣一個函數htnos:

    它是以"h”開頭的,代表“主機”;

    緊跟着它的是"to",代表“轉換到”;

    然後是"n",代表“網絡”;

    最後是"s",代表“短型數據”。

 

    你可以使用"n", "h", "to", "s", "l"的任意組合。當然,你要在可能的情況下進行組合。比如,系統是沒有stolh()函數的(Short to Long Host ?)。

    下面給出套接字字節轉換程序的列表:

    hotns()——"Host to NetWork Short",主機字節順序轉換爲網絡字節順序(對無符號短型進行操作 4bytes)

    htonl()——"Host to NetWork Long",主機字節順序轉換爲網絡字節順序(對無符號長型進行操作 8bytes)

    ntons()——"NetWork to Host short",網絡字節序轉換爲主機字節順序(對無符號短型進行操作 4bytes)

    ntohl()——"NetWork to Host Long",網絡字節順序轉換爲主機字節順序(對無符號長型進行操作 8bytes)

 

    例如:*.sin_addr.s_addr = htonl(innaddr_any)是什麼意思?

    *.sin_addr.s_addr = htonl(innaddr_any)是Socket編程中用到的。

    *是任意定義的一個sockaddr_in型的結構體對象sin_addr是他的一個屬性,用於定義IP地址,是strcut in_addr型的,s_addr爲結構體in_addr的對象,簡單說就是三個結構體嵌套包裝的一個包。

    inaddr_any一般爲內核指定的,大多數系統取0,表示任意的IP地址。

    htonl()簡單說是把一個本機IP轉化爲網絡協議中規定的格式的函數,也就是所謂的大端模式或小端模式。

    htons函數是將一個u_short類型的值從主機字節順序轉換爲TCP/IP的網絡字節順序,原型聲明如下:

    u_short  htons(u_short  hostshort);

    htonl函數是將一個u_long的值從主機字節順序轉換爲TCP/IP的網絡字節順序,原型聲明如下:

    u_long  htonl(u_long  hostlong);

    字節序和網絡平臺有關,不同的平臺,字節序不同。(字節序顧名思義——字節的排列順序)只有多於一個字節的數據類型,纔有字節序的問題,比如short或者int類型。char是沒有這個問題的字節序就是在硬件裏面,一般實在內存裏,如何表示存儲和表示這些數據類型。如果高字節放到高地址上,就是大端(big endian),如果高字節放到低地址上,就是小端模式(little endian)。

    網絡通訊中,定義網絡協議時,都指定用大端模式。所以,通用的辦法就是不管主機字節序是什麼,往網絡上發送前,都轉換成網絡字節序,也就是用htons或htonl;而從網絡收到的數據,不管主機是什麼字節序,都轉換成主機字節序,也就是ntohs或者額ntohl。按照這個規則,一般來說,不會出什麼問題了

    舉個例子,一個int型的整數在計算機中佔4個字節,那麼就有兩種排列方法:

    整數0x01020304的兩種表示方法

    低地址----------------高地址

     04      03      02      01---------------->方法1:小端模式(高字節放到低地址上)

     01      02      03      04---------------->方法2:大端模式(高字節放到高地址上)  網絡字節序

    其中,方法1和方法2的區別就是高位放到高低之還是低地址。

    爲了使得不同的主機格式能夠無歧義的和網絡格式相互賦值,一般牽涉到網絡的開發庫都會定義一套兩種格式之間的轉換函數,這樣直接使用轉換函數就可以完成兩者之間的轉換。

 

    在進行TCP通訊時,需要進行主機字節序和網絡字節的轉換。可如果我要發送的數據是調用ReadFile()函數從文件裏讀出來的,也就是讀出來的數據都是保存到char[]數組裏的,那我用send函數發送時還需要轉換字節序嗎?(http://topic.csdn.net/u/20091208/15/14925202-ce0d-4651-abfb-9e2f3cb73f1f.html)

    ——如果只是字節流,不需要轉換。一般是ip地址,端口號碼,傳輸一些整型數的參數,才需要做轉換,字節流不需要。如果頭部記錄了大小的,那麼這個記錄了大小的整型數需要轉換;

    ——協議解析方面的數字類型需要轉換,負載字節流的不需要關心;

    ——需要讓網絡認識的數據,才需要轉換,比如ip,端口號。而實際發送的數據,是沒有轉換要求的。從文件裏讀取出來的數據是你自己的數據吧,這些數據轉不轉換看你自己,反正發出去是什麼樣子,接收到就還是什麼樣子。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章