一文带你秒懂 字节序(byte order),比特序(bit order),位域(bit field)
字節(jié)序,比特序,位域
- 前言
- 引出疑惑
- 字節(jié)序
- 比特序
- 網(wǎng)卡-比特的發(fā)送和接收順序
- 大端序發(fā)送給小端序
- 小端序發(fā)送給大端序
- 位域
- 定義協(xié)議的萬能公式
前言
??不總結(jié)出來睡不著覺啊md,本來想著1點就能寫完,沒想到3點才寫完
??本文主要介紹比特序在大小端機(jī)器上的排布,以及網(wǎng)卡是如何收發(fā)比特的,文末簡單介紹了位域的約定。文章主要學(xué)習(xí)與參考字節(jié)序(byte order)和位序(bit order) 和 網(wǎng)絡(luò)字節(jié)序之大小端(字節(jié)序與比特序),這兩篇文章,在其基礎(chǔ)上修正錯誤,并繪制新圖。
??本專欄知識點是通過零聲教育的線上課學(xué)習(xí),進(jìn)行梳理總結(jié)寫下文章,對c/c++linux課程感興趣的讀者,可以點擊鏈接 C/C++后臺高級服務(wù)器課程介紹 詳細(xì)查看課程的服務(wù)。
引出疑惑
??在網(wǎng)絡(luò)編程中經(jīng)常會提到網(wǎng)絡(luò)字節(jié)序和主機(jī)序,即網(wǎng)絡(luò)字節(jié)序是大端,主機(jī)序常為小端,所以在接收或者發(fā)送數(shù)據(jù)的時候常常要進(jìn)行大小端轉(zhuǎn)換。字節(jié)序不再贅述,直接看大端與小端概念、多字節(jié)之間與單字節(jié)多部分的大小端轉(zhuǎn)換詳解(此文看大小端概念和多字節(jié)之間即可,后面的單字節(jié)寫的太垃圾了,還是看本文詳細(xì)的比較好)
??我知道字節(jié)序,大小端我懂,但是當(dāng)我看到websocket的結(jié)構(gòu)體定義,ip頭的結(jié)構(gòu)體定義的時候,我真的暈了。一個字節(jié)的8個bit居然也需要區(qū)分大小端,我真的百思不得其姐,為什么要這樣做
??昨天夜里我一直在想,難道一個字節(jié)還需要大小端??難道8個bit的存儲一個是從左往右,一個是從右往左??一搜還真是,看了好幾篇文章,但是感覺看的文章講的都不夠清楚。上面超鏈接里面寫的單字節(jié)多部分大小端其實寫的不好(因為寫的時候還不知道比特序和位域),所以特地寫此文詳細(xì)解釋比特序和位域。
字節(jié)序
??本文的重點不再字節(jié)序之上,但是后續(xù)內(nèi)容是建立在此之上的。如果不懂字節(jié)序的請先看====》大端與小端概念、多字節(jié)之間與單字節(jié)多部分的大小端轉(zhuǎn)換詳解《====看這篇文章的大端與小端概念、多字節(jié)之間內(nèi)容即可,單字節(jié)多部分的大小端轉(zhuǎn)換的原理需要看本文。
??這里我就截一張核心圖放著以方便上下文閱讀了。
比特序
??說實話我都大二開學(xué)就大三了,我居然最近才知道比特序這個名詞,屬實知識有點空洞了。那么何謂比特序呢,很好理解,就是一個字節(jié)內(nèi)的8個bit之間的順序。
- 字節(jié)序:多個字節(jié)的順序,字節(jié)與字節(jié)之間的順序
- 比特序:一個字節(jié)內(nèi),多個bit的順序,bit與bit之間的順序
??在一般情況下,比特序的順序,與字節(jié)序是保持一致的。即如果是小端字節(jié)序,那么高位bit存在高地址,低位bit存在低地址。
??我有一個很好用的辦法來區(qū)分大小端,即
- 從左往右看,如果符合我們的預(yù)期則是大端
- 從右往左看,如果符合我們的預(yù)期則是小端
??那么問題就來了,既然比特序也區(qū)分大小端,那么下面的主機(jī)序與網(wǎng)絡(luò)序的字節(jié)序轉(zhuǎn)換函數(shù),是否將比特序也一并進(jìn)行轉(zhuǎn)換了呢?
uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);??就比如上圖的194,用大端讀是194,用小端讀是35,即從左往右看和從右往左看,值是不同的。做了測試之后發(fā)現(xiàn),上面4個函數(shù)都沒有對比特序做轉(zhuǎn)換。而且寫了這么久的代碼了,也沒見系統(tǒng)提供比特序轉(zhuǎn)換的函數(shù),這就很奇怪了。
??我小端接收大端的數(shù)據(jù),大端的比特序和小端的順序不一樣,那讀出來的字面值肯定不一樣啊,咋明明沒有對比特序做任何處理,程序安然無恙呢?
??在我一開始接觸字節(jié)序的時候我就在想會不會有比特序這種東西,會不會大小端是反的,不知道讀者是否有過這種思考。
網(wǎng)卡-比特的發(fā)送和接收順序
??既然在程序中無感知,那么要么是內(nèi)核,要么是網(wǎng)卡硬件幫我們處理了。比特的發(fā)送、接收順序是指一個字節(jié)中的bit在網(wǎng)絡(luò)電纜中是如何發(fā)送、接收的。在以太網(wǎng)(Ethernet)中,是從最低比特位到最高比特位的發(fā)送順序,也就是最低比特位首先發(fā)送。
??可以看出發(fā)送順序其實是按照小端序的順序來發(fā)送的。從圖中我們可以發(fā)現(xiàn),先發(fā)低位bit再發(fā)高位bit,這樣對于接收方來說,無需知道對端是大端還是小端,這個數(shù)據(jù)最左邊一定是低位bit,右邊一定是高位bit。
??牢記這句人能看懂的話: 協(xié)議規(guī)定了先發(fā)送的bit是低位bit,后發(fā)送的是高位bit。那么先接收的一定是低位bit,后接收的一定是高位bit。至于接收之后怎么轉(zhuǎn)換順序,就看主機(jī)是什么端。
??比特的發(fā)送、接收順序?qū)PU、軟件都是不可見的,因為我們的網(wǎng)卡會給我們處理這種轉(zhuǎn)換,在發(fā)送的時候按照先發(fā)低位bit再發(fā)高位bit的順序發(fā)送比特位,在接收的時候會把接收到的比特序轉(zhuǎn),換成主機(jī)的比特序。
??所以按照這一規(guī)定,就能保證在不同的機(jī)器之間進(jìn)行通信不會發(fā)生前面擔(dān)心的字節(jié)值發(fā)生變化的問題。
大端序發(fā)送給小端序
小端序發(fā)送給大端序
位域
??何為位域?就是將一個字節(jié),分成多個區(qū)域,如下面結(jié)構(gòu)體所示,一個字節(jié)8個bit,被分成了5個區(qū)域。
??在計算機(jī)中可尋址的最小單位為字節(jié),bit是無法尋址的,但是為了抽象我們可以把計算機(jī)的最小尋址單位變成bit,也就是我們可以單獨獲得一個bit位。
??位域有一個約定:在C語言的結(jié)構(gòu)體中如果包含了位域,如果位域A定義在位域B之前,那么位域A總是出現(xiàn)在低地址的比特位。 這就決定了網(wǎng)絡(luò)編程中位域在定義時必須處理大小端問題。(同樣,結(jié)構(gòu)體中前面的成員也處于較低的地址)
struct bit_order{unsigned char a: 2,b: 3,c: 3; };??我們發(fā)現(xiàn)大小端序不同的話,abc對應(yīng)的值也會不同
unsigned char ch = 121; struct bit_order *ptr = (struct bit_order *)&ch;定義協(xié)議的萬能公式
??一般網(wǎng)絡(luò)協(xié)議都是大端序,大端序低地址存儲高位,所以如果主機(jī)是小端序,則按照協(xié)議規(guī)定反著定義位域即可。因為大小端序轉(zhuǎn)換的話,bit位置就是逆序
??舉個例子,在websocket的第一個字節(jié)中,拿FIN舉例,在大端序中它是最低地址0,在小端序中它是最高地址7。
typedef struct _ws_ophdr {unsigned char opcode: 4,rsv3: 1,rsv2: 1,rsv1: 1,fin: 1;unsigned char payload_len: 7,mask: 1; } ws_ophdr;總結(jié)
以上是生活随笔為你收集整理的一文带你秒懂 字节序(byte order),比特序(bit order),位域(bit field)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab输入二项分布函数,MATLA
- 下一篇: 输出棱形图案