背景
在我们在通过redis-cli启动交互界面时,在界面输入的set key1 value1这种命令会被redis-cli转化为特定的格式传给redis-server。这个格式就是RESP协议。
基本格式
*参数数量\r\n$参数长度\r\n参数\r\n$参数长度\r\n参数\r\n
//比如:
原始命令:set key1 value1
RESP命令:*3\r\n$4\r\nset\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n
解析:
*3\r\n //总共3个字符串
$3\r\n // 第一个字符串长度为3
set\r\n // 第一个字符串的真实数据
$4\r\n // 第二个字符串长度
key1\r\n // 第二个字符串数据
$6\r\n // 第三个字符串的长度
value1\r\n // 第三个字符串数据
RESP命令字符串拼接
// 将命令转成RESP协议格式
/**
* 将字符串数组拼接为resp协议字符串
* @param target resp协议格式命令字符串
* @param argc 参数个数
* @param argv 参数数组
* @param argvlen 参数数组中每个参数长度的数组
* @return resp命令长度
*/
int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
const size_t *argvlen)
{
// reps命令字符串声明
sds cmd;
unsigned long long totlen; //resp总长度
int j;
size_t len;
/* Abort on a NULL target */
if (target == NULL)
return -1;
/* Calculate our total size 计算resp命令总长度*/
totlen = 1+countDigits(argc)+2;
for (j = 0; j < argc; j++) {
// 每个参数的长度
len = argvlen ? argvlen[j] : strlen(argv[j]);
// 每个参数在resp实际所占长度
totlen += bulklen(len);
}
/* Use an SDS string for command construction 使用sds字符串来进行构建*/
cmd = sdsempty();
if (cmd == NULL)
return -1;
/*通过总长度进行扩容*/
cmd = sdsMakeRoomFor(cmd, totlen);
if (cmd == NULL)
return -1;
/* Construct command 构建命令 ,使用回车换行来进行分割*/
/**
* 格式:{} 表示填充,其他为命令固定格式
* *{命令字符串个数}\r\n${单个参数的长度}\r\n{}单个参数\r\n
*/
// 命令字符串个数
cmd = sdscatfmt(cmd, "*%i\r\n", argc);
for (j=0; j < argc; j++) {
// 单个字符串的长度
len = argvlen ? argvlen[j] : strlen(argv[j]);
// $后面跟字符串长度再跟回车换行
cmd = sdscatfmt(cmd, "$%u\r\n", len);
// 拼接命令到resp字符串中
cmd = sdscatlen(cmd, argv[j], len);
// 再补上回车换行
cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
}
assert(sdslen(cmd)==totlen);
*target = cmd;
return totlen;
}
``