【網路程式設計】資料傳輸時的位元組序
前言
可能小組的同學很早就聽說過大小端,但是似乎這個順序並沒有什麼卵用。。(我就是這麼想的)不過在學習網路程式設計中,突然對這個問題有了新的認識,趕緊總結下,不然以後肯定踩坑。。。
本文假定讀者已經明白了大小端的區別,並且對於網路程式設計、TCP/IP有一定了解。
正文
主機位元組序與網路位元組序的轉換
網路位元組序都是大端,但是我們用的機器多數都是小端(Intel處理器),所以在傳送資料時,我們需要轉換位元組序,同時,我們也應知道,在不同程序間通訊時常常需要考慮這個位元組序,如C編寫的程序和Java編寫的程序間通訊,(JVM也是大端)。在主機和網路位元組序的互相轉化主要涉及IP地址和埠
#include <netstat/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);
這四個函式非常明確 htonl
就是host to network long
,htons
就是host to network short
深入理解傳輸時的位元組序
在編寫網路程式時,任何格式化的資料在傳輸時都應考慮位元組序。
在總結時,我忽然想到,在之前寫聊天室時。我在將其結構體裡面的int
型別資料直接傳送,並沒有轉換順序,這樣不是應該出現錯誤嗎?因為我的機器是小端,而網路位元組序是大端呀?
對於網路位元組序,我的理解其實是一種規定。
讓我們通過一個例子說明。
我們在傳送時,傳送了一塊資料,是一個結構體。
結構體如下:
struct Test{
int flag;
char str[10];
};
struct Test a;
a.flag = 4096; // 未轉換位元組序
strcpy(a.str,"hello");
這時,如果在對端按照結構體的形式,接受資料,結果完全正確。可以順利讀出flag為4096.
通過抓包,我們可以看到,flag就是按照小端儲存的,並沒有被轉換。
而在前面呼叫htons系列函式的作用呢?
作用在於轉換了IP地址的位元組序。
(可以看到IP中的30也就是0x1e 按照大端被放在了高地址(偏移大)的位置)
埠也是同理的。
回到開頭我對位元組序理解,網路位元組序是一種規定,它規定了傳輸的資料應該按照大端,因為通訊雙方的位元組序其實是不確定的,但是按照規定我們都認為接收到的資料都是大端,即遵守規定的順序,這樣老老實實地通過htons系列函式處理格式化的資料(如int)保證了不會出現任何錯誤。
但是,我們自己寫的C/S因為都是小端,所以即使沒有遵守規定,依然可以用,但這樣並不規範,有潛在的隱患。
而對於IP地址或者埠,因為這些資料的處理全部是在應用層以下,是路由器,網絡卡進行處理,它們在設計時自然遵守規定全部依照網路位元組序對資料進行處理,而你自己不把IP地址轉換順序,交給下層處理時自然會出錯。
所以,在應用層,也應該遵守規定,對於int
double
這樣的資料也應該轉換位元組序,當然字串也挺好(這大概也就是Json的優勢了,而像protobuf這種傳輸時就要注意順序)。