之前我們在學習記憶體的時候可知,記憶體儲存資料也是有大端儲存和小端儲存的,對於網路資料流同樣有大端小端之分,那麼為什麼要定義網路位元組序呢?
原因是讓不同cpu架構的計算機進行網路通訊時,位元組序不會混淆,因此tcp/ip協議規定了在網路中傳輸的位元組流資料採用大端位元組序。
圖1-大端位元組序
通常,傳送主機通常將傳送緩衝區中的資料按記憶體位址從低到高的順序發出,接收主機把從網路上接到的位元組依次儲存在接收緩衝區中,也是按記憶體位址從低到高的順序儲存(即先發出的資料是低位址,後發出的資料是高位址)。
對於有的計算機內部使用的位元組序與網路位元組序不同的,就需要對資料進行轉換,比如ip位址,埠號,那麼可以使用下面的轉換函式。
#include
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
上面這四個函式中uint32_t表示無符號32位整數,你會發現這幾個函式都長得很類似,其中在這些函式中,h表示主機,n表示網路,to表示轉換到,l表示32位長整數的ip位址,s表示16位短整數的埠號。
這裡肯定會有一些同學有疑問,那麼ip位址為什麼是佔32位,埠號是佔16位呢?
由於埠號最大能表示65535號,那麼把65535換算成2進製就是2^16 - 1,也就是16個bit位了。
生活中人們通常需要知道自己的居住位址,在網路中的同樣需要乙個位址來唯一標識每一台主機,這樣所有的裝置之間才能實現全球通訊,ip位址就是標識了一台主機或路由裝置在網際網路的位置,並且網際網路中的所有主機都要遵守這個ip位址結構。ip協議就可以通過ip位址結構把資料**到網際網路中的目的主機。
一般ip位址的表示方法有以下三種:
二進位制記法(1000 0001 0000 1011 0000 1011 11101111),每8bit位為乙個位元組。
點分十進位制記法(可讀性高)(129 11 11 239)
十六進製制記法(登錄檔、程式設計使用)(第一種:0x810b0bef ,第二種:810b0bef 16)
為了符合人類的程式設計習慣,ip位址一般使用點分十進位制來表示的,這是為了方便區分和記憶,但是由於計算機只認識0和1,所以在計算機中ip位址也是用二進位制的0和1來表示,在程式設計中通常以十六進製制來表示ip位址。由此可知,ip位址在不同使用場景下需要進行轉換。另外,ipv4 位址本質上是 32 位無符號整數。
對於ip位址在網路中是以網路位元組序形式傳輸的,有時候需要將點分十進位制的ip位址轉換成網路位元組序的in_addr_t型別。下面這幾個函式就是對ip位址進行澱粉十進位製到in_addr_t型別之間的轉換,在早期ip位址的轉換函式只能轉換ipv4的位址。
// 將點分十進位制直接轉換成 in_addr 型別(推薦使用)
int inet_aton(const
char *cp, struct in_addr *inp);
// 將點分十進位制轉換成 in_addr_t 型別,返回值儲存的是網路位元組序(不推薦使用)
in_addr_t inet_addr(const
char *cp);
char *inet_ntoa(struct in_addr in);
下面使用的ip位址轉換函式是隨ipv6出現的新函式,對於ipv4和ipv6都支援,可以把ip位址轉換轉換成點分10進製來表示,比如:點分十進位制記法表示129.11. 11.239,這樣可讀性就顯得高很多了。
inet_pton函式用來將點分十進位制的ip位址轉換為網路位元組序,函式名中的p就表示點分十進位制,n表示網路位元組序
函式原型:
#include
int inet_pton(int af, const
char *src, void *dst);
引數說明:
af:選擇ip的版本(af_inet代表ipv4,af_inet6代表ipv6)
src:源ip位址
dst:轉換後的目標ip位址是網路位元組序(傳出引數)
返回值:
成功返回1,無效格式返回0,出錯返回-1
inet_ntop函式用來將網路位元組序轉換為點分十進位制的ip位址
函式原型:
#include
const
char *inet_ntop(int af, const
void *src, char *dst, socklen_t size);
linux早期是用sockaddr結構體來描述ipv4協議的,但是現在sockaddr結構體已經不推薦使用,因為歷史原因,套接字函式函式早期在設計時是使用的struct sockaddr結構體,後期又設計了struct sockaddr_in來替代struct sockaddr,所以當在呼叫套接字函式宣告傳遞引數的指標型別會存在問題,ansi c標準提供了解決辦法:將sockaddr定義成void *型別,也就是說sockaddr是乙個通用的套接字位址結構。
struct sockaddr ;
//使用sockaddr_in定義
struct sockaddr_in addr;
//呼叫bind函式傳參時需要對sockaddr_in型別強轉成通用的sockaddr型別
圖2-其他的套接字位址結構
sockaddr是早期用來表示ipv4位址的。
ipv4位址使用sockaddr_in結構體來表示,包括16位埠號,32為ip位址
ipv6位址用sockaddr_in6結構體表示,包括16位埠號、128位ip位址和一些控制字段
unix網路程式設計中是用sockaddr_un結構體表示,各種socket位址結構體的開頭都是相同的,前16位表示整個結構體的長度,後16位表示位址型別。
ipv4、ipv6和unix domain socket的位址型別分別定義為常數af_inet、af_inet6、af_unix。
ipv4位址用sockaddr_in結構體表示,包括16位埠號和32位ip位址,其中sin_addr成員的型別是乙個in_addr結構體,該結構體中的s_addr成員就是用來儲存ipv4的位址。
struct in_addr;
struct sockaddr_in
這樣的話,只要取得某種sockaddr結構體的首位址,就可以根據位址型別字段確定結構體中的內容,因此我們在呼叫bind、accept、connect等套接字函式,應該將這些函式的引數都用通用的套接字位址struct sockaddr *型別表示,即在傳遞引數之前先強制轉換成struct sockaddr *
型別。 網路位元組序和IP位址詳解
二 位元組序轉換函式 三 ip位址詳解 四 ip位址轉換 位元組序是指多位元組資料的儲存順序,在設計計算機系統的時候,有兩種處理記憶體中資料的方法 大端格式 小端格式。大端格式 big endian 將高位位元組資料儲存在低位址。舉個簡單的例子,對於整形 0x12345678,它在大端格式和小端格式...
ip位址 網路位元組序 主機位元組序的關係
不同的cpu有不同的位元組序型別 這些位元組序是指整數在記憶體中儲存的順序 這個叫做主機序 最常見的有兩種 1 little endian 將低序位元組儲存在起始位址 2 big endian 將高序位元組儲存在起始位址 網路位元組序用的是big endian方式,即如果乙個ip位址為 127.0....
網路程式設計 網路位元組序和位址位元組序轉化
網路位元組序是大端序,而記憶體位元組序是小端序 就像彙編學的內容一致 大端序 高位位元組存放到地位位址 小端序 高位位元組存放在高位位址 因此在位址傳輸時需要將位址進行轉化 short unsigned short htons unsigned short h to n,主機轉化成網路資料 s sh...