1. 程式人生 > >【網路程式設計】資料傳輸時的位元組序

【網路程式設計】資料傳輸時的位元組序

前言

可能小組的同學很早就聽說過大小端,但是似乎這個順序並沒有什麼卵用。。(我就是這麼想的)不過在學習網路程式設計中,突然對這個問題有了新的認識,趕緊總結下,不然以後肯定踩坑。。。

本文假定讀者已經明白了大小端的區別,並且對於網路程式設計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

,下面兩個同理,你一定知道意思,引數和返回值型別相同,long對應32bit的IP地址short對應16bit的port

深入理解傳輸時的位元組序

在編寫網路程式時,任何格式化的資料在傳輸時都應考慮位元組序
在總結時,我忽然想到,在之前寫聊天室時。我在將其結構體裡面的int型別資料直接傳送,並沒有轉換順序,這樣不是應該出現錯誤嗎?因為我的機器是小端,而網路位元組序是大端呀?

對於網路位元組序,我的理解其實是一種規定
讓我們通過一個例子說明。

我們在傳送時,傳送了一塊資料,是一個結構體。
結構體如下:

struct Test{
    int flag;
    char
str[10]; }; struct Test a; a.flag = 4096; // 未轉換位元組序 strcpy(a.str,"hello");

這時,如果在對端按照結構體的形式,接受資料,結果完全正確。可以順利讀出flag為4096.

抓包

通過抓包,我們可以看到,flag就是按照小端儲存的,並沒有被轉換。
而在前面呼叫htons系列函式的作用呢?
作用在於轉換了IP地址的位元組序。

IP
(可以看到IP中的30也就是0x1e 按照大端被放在了高地址(偏移大)的位置)

埠也是同理的。

回到開頭我對位元組序理解,網路位元組序是一種規定,它規定了傳輸的資料應該按照大端,因為通訊雙方的位元組序其實是不確定的,但是按照規定我們都認為接收到的資料都是大端,即遵守規定的順序,這樣老老實實地通過htons系列函式處理格式化的資料(如int)保證了不會出現任何錯誤。

但是,我們自己寫的C/S因為都是小端,所以即使沒有遵守規定,依然可以用,但這樣並不規範,有潛在的隱患

而對於IP地址或者埠,因為這些資料的處理全部是在應用層以下,是路由器,網絡卡進行處理,它們在設計時自然遵守規定全部依照網路位元組序對資料進行處理,而你自己不把IP地址轉換順序,交給下層處理時自然會出錯。

所以,在應用層,也應該遵守規定,對於int double 這樣的資料也應該轉換位元組序,當然字串也挺好(這大概也就是Json的優勢了,而像protobuf這種傳輸時就要注意順序)。