redis客户端(一)

最近在学习redis,顺便看了下其相关的客户端(c语言版本)的源码,在此做个简单的学习总结。

  1. 总的结构
  2. 如何交互

     

    不妨假设把abc = 123存入到redis,通过交换客户端,流程可能如下图所示


          那如何取abc的值呢,如下图

    

就是这么简单!!!

问题:

客户端和Redis底层是怎么交互这些信息的?

先介绍5种redis协议定义:

  1. simple string(一种简单的字符串) 以"+"开始,以" \r\n"结束

    eg:前面的Redis应答的OK, 则是"+0k\r\n

  2. eerrors (错误信息) 以"-"开始,以"\r\n"结束

    eg"-WRONGTYPE Operation against a key holding the wrong kind of value"
    

  3. integers(整数)以"-"开始,以"\r\n"结束
    							

    eg":1000\r\n"
    

  4. bulk strings(块字符串),这个通过一个例子来看它的格式,还是以OK为例子
    							

    "$2\r\n0K\r\n"  调整下格式方便查看    $2\r\n(第一部分,字符串长度)
    							

                                        0k\r\n (第二部分,具体字符串)
    							

    可以看出其分两部分,第一部分是字符串的长度以"$"开始,以"\r\n"结束
    							

    第二部分是局部字符串内容,也是以"\r\n"结束
    							

    两个特殊块字符串: 
    

    空字符串:"$0\r\n\r\n"
    

    NULL字符串:"$-1\r\n"
    

  5. arrays(数组),这个也通过例子来说明它的格式,比如["foo", "bar"]
    

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n" 调整格式方便查看
					

*2\r\n (数组的个数)

 $3\r\nfoo\r\n(第一个元素)
					

$3\r\nbar\r\n (第二个元素)                        

可以看出数组也是包括两部分,第一部分是数组的个数以"*"开始,以"\r\n"结束
					

第二部分是各个元素的具体内容,例子中是两个bulk strings

空数组:"*0\r\n"        
NULL数组:"*-1\r\n"

现在回头再一次来看set abc 123, 底层的传输应该是这样的(客户端发给Redis的命令都是arrays格式的)


 

  1. 客户端过程图

如上图整个过程比较清晰,也不复杂,struct redisContext{}(图中结构中有些字段并没有标出,后面出现都类似)中fd对应网络层的信息交互,接收发数据;

obuf存放是解析后的command,准备发送;从redis服务端接收到的数据放到struct redisReader中,并解析,并返回给用户。

Struct redisReader这个结构体相对比较复杂,对它进行单独说明

 

如上图所示:buf中存放从redis服务端接收的数据,待解析;struct redisReadTask rstack[9]是一个栈,它主要是用在对服务端应答数据解析用的,具体怎么使用下面进行说明;

reply是一个指向redisReply的指针,redisReply用来返回给用户的。

 

 

 

 

 

 

 

上图先列出2个结构体大致包含的内容,具体定义在下面解释如何解析redis应答数据例子中进行说明

下面通过有比较代表性的2个例子来进行说明:

一、bulkstring

 

如上图压入一个struct redisReadTask{},pos处发现是"$",知道是bulkstring类型,redisReadTask中的type 被赋值为REDIS_REPLY_STRING,

然后往后移可以知道其长度是len=3,内容是str="abc", 然后根据 len 和 str生存一个 struct redisReply(type,len,str被赋值),

struct redisReadTask{}中的obj指针指向这个struct redisReply,同时struct redisReader{}中reply也指向这个结构体

对应integers 、simple string、errors这些类型,可能就是被赋值的字段不同,如integers时,其整数值存在struct redisReply{}中的integer字段,len 和 str 就未被使用。相对复杂就是arrays类型

 

二、arrays

这是一个数组里有两个元素,一个"ab"字符串,一个数组;被包含的这个数组有一个元素,一个"cd"字符串,调整结构方便阅读

*2\r\n

$2\r\n

ab\r\n

*1\r\n

$2\r\n

Cd\rn

如上面一开始压入A1(struct redisReadTask{}) ,从pos的"*"解析 出是array,A1的type被赋值成REDIS_REPLY_ARRAY,

pos往后移动解析出这个数组有2个元素,A1的elements被 赋值为2,然后生成一个struct redisReply{}B1, 其type

和elements被赋值为同样的值, A1.obj = B1, 同时struct redisReader{}中reply也指向B1

如上图压入A2(struct redisReadTask{}) ,A2.parent = A1,A2.idx=0,这时pos在"$"处,解析出其是bulkstrings,

A2.type=REDIS_REPLY_STRING,, pos往后移动,解析出Len = 2 ,str = "ab", 根据len和 str生成一个 struct

redisReply{}B2,因为A2.parent=A1,所以B1. Element[0]= B2,可以看出前面的A2.idx就是在B1中的位置

因为前面是一个bulkstrings,所以其已经解析完成,所以 这里不再压人Struct redisReadTask{},复用A2,

A2.parent = A1,A2.idx = 1,A2.type=REDIS_REPLY_ARRAY, A2.elments = 1。原理同上,生成一个struct redisReply{}B3,

B1. Element[1]= B3,

压人Struct redisReadTask{} A3,A3.parent = A2,A3.idx = 0原理 同上,生成一个struct redisReply{} B4,B3.element[0]=B4

 

这时,因为A3.idx = A3.Ppaent.element-1,(A3.Ppaent= A2),所以是A2其最后一个元素解析完成,弹出A3;这时A2解析完成,

同时A2.idx=2,A2.idx = A2.Ppaent.element-1,,(A2.Ppaent.element= A1),所以是A1最后一个元素解析完成,弹出A2;

A1的所以元素解析完成继续弹出,这时是一个空栈,这时struct redisReader{}中reply指向的B1就是最后的结果

 

总结:

本文只是介绍了redis客户端中的最基本的一些流程,其中涉及命令的批量处理和订阅相关的内容在后续中介绍。

有任何错误或是有相关问题一起讨论,可以在下面留言。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值