Maison >base de données >Redis >Explication détaillée des exemples de mise en œuvre du protocole Redis RESP
Apprentissage recommandé : Tutoriel vidéo Redis
RESP
是基于TCP
来实现的Redis
通信协议,该协议是以/r/n
(ligne) pour la segmentation, le protocole prend en charge 5 types, les informations spécifiques sont les suivantes :
type | préfixe | Remarques |
---|---|---|
Chaîne simple | + | Chaîne simple commence par + |
Données d'erreur | - | Les données d'erreur commencent par - |
Entier | : | Les entiers commencent par : |
Chaîne complexe | $ | Chaîne complexe commence par $ |
Array | * | Array commence par * |
即,我们向redis
发送命令:set name pdudo
,其实发送的具体信息是
*3 $3 set $4 name $5 pdudo
而服务器返回的信息也是类似的,只不过还需要了解+
和-
,这2个前缀分别代表正确消息和错误的消息。
我们准备2个例子,我们来敲一下
例子1
set name pdudo
例子2
lpush pdudo data1 lpush pdudo data2 lrange pdudo 0 -1
快来动动你的小手指,看能不能根据RESP
协议规则,将上述例子命令敲出来。现在你体会到了Redis
官网介绍RESP
协议时所述的 简单 和 易读 可么?
对于RESP
来说,一定要搞清楚协议后,最好能够手写协议去执行,再考虑写程序去实现协议!!!
终于到了喜闻乐见的环节了,我们要拆解和组装协议了。 那我们至少来解决如下3个问题:
TCP
流的,我们如何判断整个命令什么时候结束?协议什么时候结束
一般而言,我们自己在使用TCP
传输数据,都会在数据开头定义2个或者4个字节,用于存储该数据有多少个字节,这样方便检验接收,类似于这种情况。
而RESP
有意思了,它是以/r/n
来分割的。最前面会以前缀来判断其类型,例如我们发送命令,其会用到的前缀有*
以及$
,那么我们如何来判断,我们要读取多少个/r/n
呢?
因为上述*
代表数组,即有多少组数据需要处理,图中为n
。
而$
表示复杂字符串,即需要获取m
个字符数据,不包含/r/n
如何拆解RESP
协议
若要拆解命令,则我们得获取命令,如上图所示,报文$m
,其实记录的有m
长度的数据(不包含\r\n
),所以我们可以这样来写伪代码。
根据如上,我们很容易写出伪代码。
func toArgs(rd *bufio.Reader) { data , _ , _ := rd.ReadLine() switch data[0] { case '*': n := data[1:] // 循环n次 for i:=0;i<n;i++ { toArgs(rd) } case '$': m := data[1:] // 获取m个数据 // 获取m长度的数据即可 } }
如上我们先获取前缀为*
的,继而获取其值n
,我们则循环n
次,即可获取该报文的数据。而前缀为$
的,我们可以直接获取该m
长度的数据即可,这里主要要处理一下\r\n
。
将命令构建RESP
报文规范,根据拆解反操作就可以了,这里暂不介绍了。
上述,我们核心功能已经探讨完毕了。
代码已经编写完毕,放置在了gitee
上: gitee
如上我们已经学会了如何拆解和组装RESP
协议了,我们接着来看,我们如何用go
来编写拆解和组装协议的代码呢? 我们可以看。
我们先创建一个字符,然后将其封装为bufio.Reader
,我们来看下:
因为我们要使用readLine()
函数,所以我们需要将其转换为bufio.Reader
类型,若是直接从net.Conn
中获取,不用转换,直接可以使用 bufio.Reader
的。
我们将上述伪代码编写一下,实现拆解的功能。
其具体执行过程是我们先获取一行数据,放置到data
中,而后判断其前缀是什么,若是*
则取其后面的数据,将其转为int
类型n
,而后再递归该函数n
次,而后中遇到$
,我们则取后面的数据,也是将其转为int
类型m
,而后再取m
长度的实际数据,这就是我们的命令了,最后我们再踢掉命令的\r\n
即可。
其中,有一个函数是byteToInt
是我们自己写的通过切片转为数字的函数,我们看下
该函数主要的功能是将其[]byte
数字转换为int
数据。
如上,我们整个RESP
协议功能写完了,我们运行下看下实际效果:
Évidemment, nous avons réussi à démonter les données.
Dans cet article, nous expliquons comment utiliser go
pour démonter simplement le contenu du protocole RESP
. Pourquoi ne pas présenter comment écrire redis<.> Qu'en est-il du middleware maître-esclave ? <code>go
简单的拆解RESP
协议的内容,为什么我们不介绍如何编写redis
主从中间件呢?
最开始是打算这样写的,但是知识多了,介绍起来会很杂,很难把一个点讲清楚,所以我们就单独挑了一个核心点来介绍,我愿意将其称之为面向核心编程(我的基友很早之前告诉我的),所谓的面向核心编程简而易在就是我们在涉及一个功能的时候,要学会拆解该功能,将核心功能先用demo
做出来,而后再慢慢丰富周边,从而完成整个需求涉及。
最后我们再来聊聊RESP
J'avais initialement prévu de l'écrire comme ça, mais avec trop de connaissances, l'introduction sera très compliquée et il est difficile d'expliquer clairement un point, nous avons donc simplement choisi un point central à introduire que j'aimerais l'appeler. Programmation orientée cœur (mon ami me l'a dit il y a longtemps), la programmation dite orientée cœur est simple et facile. Lorsque nous sommes impliqués dans une fonction, nous devons apprendre à démonter la fonction et à utiliser demo<. pour la fonction principale le code> est d'abord créé, puis enrichit lentement les zones environnantes pour compléter l'ensemble des exigences. </.>
Enfin, parlons du protocole RESP
. Le site officiel le résume comme suit : mise en œuvre simple, analyse rapide
directement lisible. Si vous étudiez attentivement ces deux articles, vous en aurez certainement une profonde compréhension.
Apprentissage recommandé : 🎜Tutoriel vidéo Redis🎜🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!