計(jì)算機(jī)網(wǎng)絡(luò)編程中一個非常基本的問題:該怎樣表示client與server之間交互的數(shù)據(jù),在往下看之前先想一想這個問題。
共識與協(xié)議
這個問題可不像看上去的那樣簡單,因?yàn)閏lient進(jìn)程和server進(jìn)程運(yùn)行在不同的機(jī)器上,這些機(jī)器可能運(yùn)行在不同的處理器平臺、可能運(yùn)行在不同的操作系統(tǒng)、可能是由不同的編程語言編寫的,server要怎樣才能識別出client發(fā)送的是什么數(shù)據(jù)呢?就像這樣:client給server發(fā)送了一段數(shù)據(jù):
0101000100100001
server怎么能知道該怎樣“解讀”這段數(shù)據(jù)呢?
顯然,client和server在發(fā)送數(shù)據(jù)之前必須首先達(dá)成某種關(guān)于怎樣解讀數(shù)據(jù)的共識,這就是所謂的 協(xié)議 。
這里的協(xié)議可以是這樣的:“將每8個比特為一個單位解釋為無符號數(shù)字”,如果協(xié)議是這樣的,那么server接收到這串二進(jìn)制后就會將其解析為81(01010001)與33(00100001)。
當(dāng)然,這里的協(xié)議也可以是這樣的:“將每8個比特為一個單位解釋為ASCII字符”,那么server接收到這串二進(jìn)制后就將其解析為“Q!”。
可見,同樣一串二進(jìn)制在不同的“上下文/協(xié)議”下有完全不一樣的解讀,這也是為什么計(jì)算機(jī)明明只認(rèn)知0和1但是卻能處理非常復(fù)雜任務(wù)的根本原因,因?yàn)橐磺卸伎梢跃幋a為0和1,同樣的我們也可以從0和1中解析出我們想要的信息,這就是所謂的編解碼技術(shù)。
實(shí)際上不止0和1,我們也可以將信息編碼為摩斯密碼(Morse code)等,只不過計(jì)算機(jī)擅長處理0和1而已。
扯遠(yuǎn)了,回到本文的主題。
遠(yuǎn)程過程調(diào)用:RPC
作為程序員我們知道,client以及server之間不會簡單傳遞一串?dāng)?shù)字以及字符這樣簡單,尤其在互聯(lián)網(wǎng)大廠后端服務(wù)這種場景下。
當(dāng)我們在電商App搜索商品、打車App呼叫出租車以及刷短視頻時,每一次請求的背后在后端都涉及大量服務(wù)之間的交互,就像這樣:
完成一次客戶端請求gateway這個服務(wù)要調(diào)用N多個下游服務(wù),所謂調(diào)用是說A服務(wù)向B服務(wù)發(fā)送一段數(shù)據(jù)(請求),B服務(wù)接收到這段數(shù)據(jù)后執(zhí)行相應(yīng)的函數(shù),并將結(jié)果返回給A服務(wù)。
只不過對于服務(wù)A來說并不想關(guān)心網(wǎng)絡(luò)傳輸這樣的底層細(xì)節(jié),如果能像調(diào)用本地函數(shù)一樣調(diào)用遠(yuǎn)程服務(wù)就好了,這就是所謂的RPC,經(jīng)典的實(shí)現(xiàn)方式是這樣的:
RPC對上層提供和普通函數(shù)一樣的接口,只不過在實(shí)現(xiàn)上封裝了底層復(fù)雜的網(wǎng)絡(luò)通信,RPC框架是當(dāng)前互聯(lián)網(wǎng)后端的基石之一,很多所謂互聯(lián)網(wǎng)后端的職位無非就是在此基礎(chǔ)之上堆業(yè)務(wù)邏輯。
本文我們不關(guān)心其中的細(xì)節(jié),這里我們只關(guān)心在網(wǎng)絡(luò)層client是怎樣對請求參數(shù)進(jìn)行編碼、server怎樣對請求參數(shù)進(jìn)行解碼的,也就是本文開頭提出的問題。
信息的編解碼
在思考怎樣進(jìn)行編解碼之前我們必須意識到:
- client和server可能是用不同語言編寫的,你的編解碼方案必須通用且不能和語言綁定
- 編解碼方法的性能問題,尤其是對時間要求苛刻的服務(wù)
首先,我們最應(yīng)該能想到的就是以純文本的形式來表示。
純文本從來都是一種非常有友好的信息載體,為什么?很簡單,因?yàn)槿祟?我們)可以直接看懂,就像這段:
{
"widget": {
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
},
}
}
是不是很清晰,一目了然,只要我們實(shí)現(xiàn)約定好文本的結(jié)構(gòu)(也就是語法),那么client和server就能利用這種文本進(jìn)行信息的編碼以及解碼,不管client和server是運(yùn)行在x86還是Arm、是32位的還是64位的、運(yùn)行在Linux上還是windows上、是大端還是小端,都可以無障礙交流。
因此在這里,文本的語法就是一種協(xié)議。順便說一句, 你都規(guī)定好了文本的語法,實(shí)際上就相當(dāng)于發(fā)明了一種語言 。
這里用來舉例用的語言就是所謂的Json,只不過json這種語言不是用來表示邏輯(代碼)而是用來存儲數(shù)據(jù)的。
Json就是這個老頭提出來的:
除了Json,另一種利用文本存儲數(shù)據(jù)的表示方法是XML,來一段感受下:
<note>
<to>Toveto>
<from>Janifrom>
<heading>Reminderheading>
<body>Don't forget me this weekend!body>
note>
相對Json來說是不是就沒那么容易看懂了,Json出現(xiàn)后在web領(lǐng)域逐漸取代了XML。
當(dāng)兩段數(shù)據(jù)量很少的時候——就像瀏覽器和服務(wù)端的交互,Json可以工作的非常好,這個場景就是這里:在這里是json的天下。
但對于后端服務(wù)之間的交互來說就不一樣了,后端服務(wù)之間的RPC調(diào)用可能會傳輸大量數(shù)據(jù),如果全部用純文本的形式來表示數(shù)據(jù)那么不管是網(wǎng)絡(luò)帶寬還是性能可能都會差強(qiáng)人意。
在這種場景下,Json并不是最好的選項(xiàng),主要原因之一就在于性能以及數(shù)據(jù)的體積。
我們知道,文本表示對人類是最友好的,對機(jī)器來說則不是這樣,對機(jī)器來說最好的還是01二進(jìn)制。
那么有沒有二進(jìn)制的編碼方法嗎?答案是肯定的,這就是當(dāng)前互聯(lián)網(wǎng)后端中流行的protobuf,Google公司開源項(xiàng)目。
那么protobuf有什么神奇之處嗎?
假設(shè)client端想給server端傳輸這樣一段信息:“我有一個id,其值為43”,那么在XML下是這樣表示的:
<id>43id>
數(shù)一數(shù)這這段數(shù)據(jù)占據(jù)了多少字節(jié),很顯然是11字節(jié);
而如果用json來表示呢?
{"id":43}
數(shù)一數(shù)這段數(shù)據(jù)占據(jù)了多少字節(jié),顯然是9字節(jié);
而如果用protobuf來表示呢? 是這樣的:
// 消息定義
message Msg {
optional int32 id = 1;
}
// 實(shí)例化
Msg msg;
msg.set_id(43);
其中Msg的定義看上去比Json和XML更加復(fù)雜了,但這些只是給人看的,這些還會被protbuf進(jìn)一步處理,最終被編碼為:
082b
也就是0x08與0x2b,這占據(jù)了多少字節(jié)呢?答案是2字節(jié)。
從json的9字節(jié)到protobuf的2字節(jié),數(shù)據(jù)大小減少了4倍多,數(shù)據(jù)量的減少意味著:
- 更少的網(wǎng)絡(luò)帶寬
- 更快的解析速度
那么protobuf是怎樣做到這一點(diǎn)的呢?
-
計(jì)算機(jī)
+關(guān)注
關(guān)注
19文章
7540瀏覽量
88650 -
Server
+關(guān)注
關(guān)注
0文章
93瀏覽量
24118 -
網(wǎng)絡(luò)編程
+關(guān)注
關(guān)注
0文章
72瀏覽量
10104
發(fā)布評論請先 登錄
相關(guān)推薦
探討2對4二進(jìn)制解碼器及4到16二進(jìn)制解碼器配置
![探討2對4<b class='flag-5'>二進(jìn)制</b><b class='flag-5'>解碼</b>器及4到16<b class='flag-5'>二進(jìn)制</b><b class='flag-5'>解碼</b>器配置](https://file.elecfans.com/web1/M00/D8/0A/pIYBAF_qquOAL65sAAAXWexEff4436.png)
二進(jìn)制相對調(diào)相(二進(jìn)制差分調(diào)相2DPSK)的工作原理
![<b class='flag-5'>二進(jìn)制</b>相對調(diào)相(<b class='flag-5'>二進(jìn)制</b>差分調(diào)相2DPSK)的工作原理](https://file1.elecfans.com//web2/M00/A4/6C/wKgZomUMNCaAJPaQAADMOGqmdHg823.jpg)
二進(jìn)制
![<b class='flag-5'>二進(jìn)制</b>](https://file1.elecfans.com//web2/M00/A4/B5/wKgZomUMNVyAdVirAAASM9n2nZE370.gif)
同步二進(jìn)制計(jì)數(shù)器
![同步<b class='flag-5'>二進(jìn)制</b>計(jì)數(shù)器](https://file1.elecfans.com//web2/M00/A5/4A/wKgZomUMN8GAMYnPAAA5XUKDLs8264.jpg)
二進(jìn)制編碼和二進(jìn)制數(shù)據(jù)
二進(jìn)制數(shù)的運(yùn)算規(guī)則
什么是二進(jìn)制計(jì)數(shù)器,二進(jìn)制計(jì)數(shù)器原理是什么?
二進(jìn)制電平,什么是二進(jìn)制電平
二進(jìn)制加法程序【匯編版】
二進(jìn)制加法程序【C語言版】
二進(jìn)制數(shù)據(jù)壓縮算法
二進(jìn)制解碼器到底是什么
![<b class='flag-5'>二進(jìn)制</b><b class='flag-5'>解碼</b>器到底是什么](http://p2.itc.cn/q_70/images03/20201228/2f86cca955c64727979a3d2edb4119a4.png)
二進(jìn)制解碼器開源設(shè)計(jì)
![<b class='flag-5'>二進(jìn)制</b><b class='flag-5'>解碼</b>器開源設(shè)計(jì)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論