Linux網路程式設計 之 大小端初探

2021-08-18 07:21:21 字數 2955 閱讀 6037

首先解釋一下大小端的概念。

大端(big endian),同時也是網路序,是資料在網路上傳輸的一種資料組織格式,其儲存的方式比較符合人們讀寫的習慣。

小端(little endian),這裡不能說其是主機序,因為主機可能採用的是大端cpu也可能採用的是小端cpu,小端與大端相對。

通過乙個例子深入了解它們之間的區別:

用一台big endian 和 另一台 little endian 分別儲存32bit的數值,為:0x12345678,資料在記憶體當中的儲存順序如下表所示。

addr

big endian

little endian

0xa0x12

0x78

0xb0x34

0x56

0xc0x56

0x34

0xd0x78

0x12

由表1可以清晰看到,在大端;在小端計算機當中,可以總結為八個字:小端(低位元組)存在起始位址。我們深入了解位元組在計算機當中的儲存方式,仍以0x12345678為例。

32 bit representation in memory:

decimal: ‭305419896‬

從上面的資料分布,可以發現乙個規律,不論大小端,他們儲存位元組,位元組當中的bit位相對順序一樣的,由此,給我們大小端互相轉換提供了思路,利用位運算和移位運算。實際上linux已經為我們提供了位元組序轉換的api,我們可以在linux終端下令入:man htonl 即可檢視到使用此函式所需要包含的標頭檔案,用法等,鍵入後得到結果如下圖所示:

現在我們去找一下htonl 的linux實現**,由於linux的標頭檔案基本都在/usr/include下,因此我們直接利用linux提供的find工具去進行搜尋:在終端鍵入

find /usr/include/ -type f | xargs grep -n htonl

得到結果如下:

紅色的兩句對我們而言是比較有用的兩句,從上面可以看到,htonl其實是__int32_identify 和 __bsway_32的巨集替換,我們鍵入命令開啟檔案 /usr/include/netinet/in.h檢視並定位到行397(vim 下鍵入":"並輸入行號即可定位到相應行)。

vim /usr/include/netinet/in.h

得到如下結果:

得知乙個是用於大端的轉換(其實大端已經沒有必要轉,網路流進主機的資料,就是大端的)我們可以猜想,這個__int32_identify是乙個類似#define__int32_identify(x) x空的巨集定義或者乙個直接將傳入引數返回的函式,事實證明ubuntu中採用的的是後者,並且使用了內連函式。我們繼續查詢__bsway_32,因為這個函式的實現才是我們所關心的,在終端鍵入:

find /usr/include/ -type f | xargs grep -n __bswap_32

得到如下結果:

紅色框起來的部分資訊就是我們所尋找的資訊,開啟檔案byteswap.h並定位到45行

從**當中可以看到,針對不同的編譯器版本,提供了不同的位元組轉換,有使用編譯器內建的函式,也有使用彙編實現的位元組序的轉換,同時也有**自己實現的__bswap_constant_32(x),這也正是我們所關注的,可以看到,這個巨集定義的實現,正是採用移位運算和位運算完成位元組序的轉換。

#define __bswap_constant_32(x) \

((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \

(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

我們分析一下這個巨集定義,例如小端上儲存的為0x78563412,由上面的分析得知網路序其實是0x12345678,我們用這個函式證實一下:

0x78563412 & 0xff000000 值為 0x78000000 ,左移24bit即 0x00000078

0x78563412 & 0x00ff0000 值為 0x00560000 ,左移 8bit 即 0x00005600

0x78563412 & 0x0000ff00 值為 0x00003400 ,右移 8bit 即 0x00340000

0x78563412 & 0x000000ff 值為 0x00000012 ,右移24bit即 0x12000000

最後將右側的結果按位與得到結果0x12345678,結果符合我們的猜想。

從網路序轉換為主機序的分析思路與此完全一致,有興趣的盆友可自行動手試探一番。

好啦,位元組序轉換初步寫到這裡,這裡僅僅介紹了位元組間的轉換,並沒有分析跨位元組位域怎麼儲存和我們怎麼轉換和存值,欲知後事,請聽下回分析~

網路程式設計之大小端

在計算機的資料儲存中,有2種的儲存方式,就是大小端,大端指的是高位資料儲存在低位的位址,低位資料放高位,小端則相反,我們了解清這一點很重要,因為要保證資料的一致性,傳送端和接收端就應該協商好用哪種儲存方式來傳送和接收。include includeusing namespace std int ma...

linux網路程式設計 初探TCP

伺服器端等待客戶端連線,連線成功後,列印客戶端的ip和port,然後迴圈接收資料,緩衝區無資料就阻塞待待。include include include include include include include include include include define maxbuf 10 ...

Socket網路程式設計之Client端

socket inetaddress string remoteaddress,int port 建立連線到指定遠端主機 遠端埠的socket,該構造器沒有指定本地位址 本地埠,預設使用本地主機的預設ip位址,預設使用系統動態指定的ip位址。socket inetaddress string rem...