Redis C/S 间数据交互「二」|小册免费学

上一篇:juejin.cn/post/695623…

RESP3

先整体列举一下:

NULL

代表 resp2 中的 *-1\r\n 或者 $-1\r\n

_\r\n
复制代码

Double

,1.23\r\n
复制代码

Boolean

#t\r\n
#f\r\n
复制代码

二进制安全的error

!21\r\nSYNTAX invalid syntax\r\n
复制代码

Verbatim string

=15<CR><LF>
txt:Some string<CR><LF>
复制代码

Verbatim string

=15<CR><LF>
txt:Some string<CR><LF>
复制代码

Map

%2<CR><LF>
+first<CR><LF>
:1<CR><LF>
+second<CR><LF>
:2<CR><LF>
复制代码

Set

~5<CR><LF>
+orange<CR><LF>
+apple<CR><LF>
#t<CR><LF>
:100<CR><LF>
:999<CR><LF>
复制代码

Hello

建立连接时,返回服务端名称,版本等等

# 发送这个,可以切换成 RESP3
HELLO 3
复制代码

接收

  1. server 端接收到命令首先存储在客户端对象的 querybuf 输入缓冲区
  2. 然后开始解析命令,各个参数;并存储在客户端对象的 argv(参数对象),argc(参数数目)

来说说第2个,具体的解析过程:

  1. 解析请求参数数目
  2. 循环解析每个请求参数

参数数目

走的是多行解析, processMultibulkBuffer ,那么第一个字符 * 得识别出来:

// 读入命令的参数个数
// 比如 *3\r\n$3\r\nSET\r\n... 将令 c->multibulklen = 3
if (c->multibulklen == 0) {
  redisAssertWithInfo(c,NULL,c->argc == 0);

  // 检查缓冲区的内容第一个 "\r\n"
  newline = strchr(c->querybuf,'\r');
  ...
  // 协议的第一个字符必须是 '*'
  redisAssertWithInfo(c,NULL,c->querybuf[0] == '*');
  // 将参数个数,也即是 * 之后, \r\n 之前的数字取出并保存到 ll 中
  // 比如对于 *3\r\n ,那么 ll 将等于 3
  // ----> 【C语言的多返回值操作】很秀:&ll
  ok = string2ll(c->querybuf+1,newline-(c->querybuf+1),&ll);
  // 参数的数量超出限制
  if (!ok || ll > 1024*1024) {
    addReplyError(c,"Protocol error: invalid multibulk length");
    setProtocolError(c,pos);
    return REDIS_ERR;
  }

  // 参数数量之后的位置
  // 比如对于 *3\r\n$3\r\nSET\r\n... 来说,
  // pos 指向 *3\r\n$3\r\nSET\r\n...
  //                ^
  //                |
  //               pos
  // 记录已解析位置偏移量
  pos = (newline-c->querybuf)+2;
  // 如果 ll <= 0 ,那么这个命令是一个空白命令
  ...
  // 设置参数数量
  c->multibulklen = ll;
  ...
}
复制代码

循环解析参数

上述结束时出来的协议:$3\r\nSET\r\n

// 读入参数长度
if (c->bulklen == -1) {
  // 确保 "\r\n" 存在
  newline = strchr(c->querybuf+pos,'\r');
  ...
  // 确保协议符合参数格式,检查其中的 $...
  // 比如 $3\r\nSET\r\n
  if (c->querybuf[pos] != '$') {
    return REDIS_ERR;
  }

  // 读取长度
  // 比如 $3\r\nSET\r\n 将会让 ll 的值设置 3
  ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll);
  ...
  // 定位到参数的开头
  // 比如 
  // $3\r\nSET\r\n...
  //       ^
  //       |
  //      pos
  pos += newline-(c->querybuf+pos)+2;
  ...
  // 参数的长度
  c->bulklen = ll;
}
复制代码

解析出来参数字符串长度之后:

  1. 创建字符串对象
  2. 更新 multibulklenmultibulklen--

multibulklen 更新到0,说明参数解析完毕。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享