Redis?RESP?協(xié)議實(shí)現(xiàn)實(shí)例詳解
引言
我們之前已經(jīng)學(xué)習(xí)了RESP
協(xié)議的內(nèi)容,且已經(jīng)完成了一個(gè)最簡(jiǎn)單的Redis
讀寫(xiě)分離中間件,我們來(lái)看拆解下該demo
, 看看Redis RESP
協(xié)議實(shí)現(xiàn)起來(lái)到底有多簡(jiǎn)單。
回顧RESP協(xié)議
RESP
是基于TCP
來(lái)實(shí)現(xiàn)的Redis
通信協(xié)議,該協(xié)議是以/r/n
(行)進(jìn)行分割的,協(xié)議支持5種類(lèi)型,具體信息如下:
類(lèi)型 | 前綴 | 備注 |
---|---|---|
簡(jiǎn)單字符串 | + | 簡(jiǎn)單字符串以+開(kāi)頭 |
錯(cuò)誤數(shù)據(jù) | - | 錯(cuò)誤數(shù)據(jù)以-開(kāi)頭 |
整數(shù) | : | 整數(shù)以:開(kāi)頭 |
復(fù)雜字符串 | $ | 復(fù)雜字符串以$開(kāi)頭 |
數(shù)組 | * | 數(shù)組以*開(kāi)頭 |
即,我們向redis
發(fā)送命令:set name pdudo
,其實(shí)發(fā)送的具體信息是
*3 $3 set $4 name $5 pdudo
而服務(wù)器返回的信息也是類(lèi)似的,只不過(guò)還需要了解+
和-
,這2個(gè)前綴分別代表正確消息和錯(cuò)誤的消息。
我們準(zhǔn)備2個(gè)例子,我們來(lái)敲一下
例子1
set name pdudo
例子2
lpush pdudo data1 lpush pdudo data2 lrange pdudo 0 -1
快來(lái)動(dòng)動(dòng)你的小手指,看能不能根據(jù)RESP
協(xié)議規(guī)則,將上述例子命令敲出來(lái)。現(xiàn)在你體會(huì)到了Redis
官網(wǎng)介紹RESP
協(xié)議時(shí)所述的 簡(jiǎn)單 和 易讀 可么?
帶著來(lái)敲一下
對(duì)于RESP
來(lái)說(shuō),一定要搞清楚協(xié)議后,最好能夠手寫(xiě)協(xié)議去執(zhí)行,再考慮寫(xiě)程序去實(shí)現(xiàn)協(xié)議!??!
如何拆解RESP協(xié)議
終于到了喜聞樂(lè)見(jiàn)的環(huán)節(jié)了,我們要拆解和組裝協(xié)議了。 那我們至少來(lái)解決如下3個(gè)問(wèn)題:
- 該協(xié)議是基于
TCP
流的,我們?nèi)绾闻袛嗾麄€(gè)命令什么時(shí)候結(jié)束? - 如何拆解命令?
協(xié)議什么時(shí)候結(jié)束
一般而言,我們自己在使用TCP
傳輸數(shù)據(jù),都會(huì)在數(shù)據(jù)開(kāi)頭定義2個(gè)或者4個(gè)字節(jié),用于存儲(chǔ)該數(shù)據(jù)有多少個(gè)字節(jié),這樣方便檢驗(yàn)接收,類(lèi)似于這種情況。
而RESP
有意思了,它是以/r/n
來(lái)分割的。最前面會(huì)以前綴來(lái)判斷其類(lèi)型,例如我們發(fā)送命令,其會(huì)用到的前綴有*
以及$
,那么我們?nèi)绾蝸?lái)判斷,我們要讀取多少個(gè)/r/n
呢?
因?yàn)樯鲜?code>*代表數(shù)組,即有多少組數(shù)據(jù)需要處理,圖中為n
。
而$
表示復(fù)雜字符串,即需要獲取m
個(gè)字符數(shù)據(jù),不包含/r/n
如何拆解RESP
協(xié)議
若要拆解命令,則我們得獲取命令,如上圖所示,報(bào)文$m
,其實(shí)記錄的有m
長(zhǎng)度的數(shù)據(jù)(不包含\r\n
),所以我們可以這樣來(lái)寫(xiě)偽代碼。
根據(jù)如上,我們很容易寫(xiě)出偽代碼。
func toArgs(rd *bufio.Reader) { data , _ , _ := rd.ReadLine() switch data[0] { case '*': n := data[1:] // 循環(huán)n次 for i:=0;i<n;i++ { toArgs(rd) } case '$': m := data[1:] // 獲取m個(gè)數(shù)據(jù) // 獲取m長(zhǎng)度的數(shù)據(jù)即可 } }
如上我們先獲取前綴為*
的,繼而獲取其值n
,我們則循環(huán)n
次,即可獲取該報(bào)文的數(shù)據(jù)。而前綴為$
的,我們可以直接獲取該m
長(zhǎng)度的數(shù)據(jù)即可,這里主要要處理一下\r\n
。
將命令構(gòu)建RESP
報(bào)文規(guī)范,根據(jù)拆解反操作就可以了,這里暫不介紹了。
上述,我們核心功能已經(jīng)探討完畢了。
功能實(shí)現(xiàn)
代碼已經(jīng)編寫(xiě)完畢,放置在了gitee
上: gitee
如上我們已經(jīng)學(xué)會(huì)了如何拆解和組裝RESP
協(xié)議了,我們接著來(lái)看,我們?nèi)绾斡?code>go來(lái)編寫(xiě)拆解和組裝協(xié)議的代碼呢? 我們可以看。
我們先創(chuàng)建一個(gè)字符,然后將其封裝為bufio.Reader
,我們來(lái)看下:
因?yàn)槲覀円褂?code>readLine()函數(shù),所以我們需要將其轉(zhuǎn)換為bufio.Reader
類(lèi)型,若是直接從net.Conn
中獲取,不用轉(zhuǎn)換,直接可以使用 bufio.Reader
的。
我們將上述偽代碼編寫(xiě)一下,實(shí)現(xiàn)拆解的功能。
其具體執(zhí)行過(guò)程是我們先獲取一行數(shù)據(jù),放置到data
中,而后判斷其前綴是什么,若是*
則取其后面的數(shù)據(jù),將其轉(zhuǎn)為int
類(lèi)型n
,而后再遞歸該函數(shù)n
次,而后中遇到$
,我們則取后面的數(shù)據(jù),也是將其轉(zhuǎn)為int
類(lèi)型m
,而后再取m
長(zhǎng)度的實(shí)際數(shù)據(jù),這就是我們的命令了,最后我們?cè)偬叩裘畹?code>\r\n即可。
其中,有一個(gè)函數(shù)是byteToInt
是我們自己寫(xiě)的通過(guò)切片轉(zhuǎn)為數(shù)字的函數(shù),我們看下
該函數(shù)主要的功能是將其[]byte
數(shù)字轉(zhuǎn)換為int
數(shù)據(jù)。
如上,我們整個(gè)RESP
協(xié)議功能寫(xiě)完了,我們運(yùn)行下看下實(shí)際效果:
很顯然,我們成功拆解了該數(shù)據(jù)。
總結(jié)
這篇文章,我們介紹了應(yīng)該如何使用go
簡(jiǎn)單的拆解RESP
協(xié)議的內(nèi)容,為什么我們不介紹如何編寫(xiě)redis
主從中間件呢?
最開(kāi)始是打算這樣寫(xiě)的,但是知識(shí)多了,介紹起來(lái)會(huì)很雜,很難把一個(gè)點(diǎn)講清楚,所以我們就單獨(dú)挑了一個(gè)核心點(diǎn)來(lái)介紹,我愿意將其稱(chēng)之為面向核心編程(我的基友很早之前告訴我的),所謂的面向核心編程簡(jiǎn)而易在就是我們?cè)谏婕耙粋€(gè)功能的時(shí)候,要學(xué)會(huì)拆解該功能,將核心功能先用demo
做出來(lái),而后再慢慢豐富周邊,從而完成整個(gè)需求涉及。
最后我們?cè)賮?lái)聊聊RESP
協(xié)議,官網(wǎng)在介紹時(shí)將其概括為實(shí)現(xiàn)簡(jiǎn)單、快速解析、直接可閱讀。如果你認(rèn)真學(xué)習(xí)這2篇文章,肯定對(duì)此深有感悟。
更多關(guān)于Redis RESP 協(xié)議的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Redis底層數(shù)據(jù)結(jié)構(gòu)之dict、ziplist、quicklist詳解
本文給大家詳細(xì)介紹了Redis的底層數(shù)據(jù)結(jié)構(gòu):dict、ziplist、quicklist的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-09-09redis中的數(shù)據(jù)結(jié)構(gòu)和編碼詳解
本文主要和大家分享幾種Redis數(shù)據(jù)結(jié)構(gòu)詳解,希望文中的案例和代碼,能幫助到大家。2020-03-03Redis實(shí)現(xiàn)附近商鋪的項(xiàng)目實(shí)戰(zhàn)
本文主要介紹了Redis實(shí)現(xiàn)附近商鋪的項(xiàng)目實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Springboot/Springcloud項(xiàng)目集成redis進(jìn)行存取的過(guò)程解析
大家都知道Redis支持五種數(shù)據(jù)類(lèi)型:string(字符串),hash(哈希),list(列表),set(集合),zset(sorted set:有序集合),本文重點(diǎn)給大家介紹Springboot/Springcloud項(xiàng)目集成redis進(jìn)行存取的過(guò)程,需要的朋友參考下吧2021-12-12Redis筆記點(diǎn)贊排行榜的實(shí)現(xiàn)示例
探店筆記類(lèi)似點(diǎn)評(píng)網(wǎng)站的評(píng)價(jià),本文主要介紹了Redis筆記點(diǎn)贊排行榜的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01windows環(huán)境下Redis+Spring緩存實(shí)例講解
這篇文章主要為大家詳細(xì)介紹了windows環(huán)境下Redis+Spring緩存實(shí)例教程,感興趣的小伙伴們可以參考一下2016-04-04