Redis 通信协议

# 简介

几乎所有的主流编程语言都有Redis的客户端(http://redis.io/clients),不考虑Redis非常流行的原因,如果站在技术的角度看原因还有两个:

  1. 客户端与服务端之间的通信协议是在 TCP 协议之上构建的。

    客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 。

    客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾。

  2. Redis制定了 RESP(REdis Serialization Protocol,Redis序列化协议)实现客户端与服务端的正常交互,这种协议简单高效,既能够被机器解析,又容易被人类识别。

    发送命令

    RESP 在 Redis 1.2 版本中引入, 并最终在 Redis 2.0 版本成为 Redis 服务器通信的标准方式。

    在这个协议中, 所有发送至 Redis 服务器的参数都是二进制安全(binary safe)的。

    RESP 的规定一条命令的格式如下:

    *<参数数量> CR LF
    $<参数 1 的字节数量> CR LF
    <参数 1 的数据> CR LF
    ...
    $<参数 N 的字节数量> CR LF
    <参数 N 的数据> CR LF

    命令本身也作为协议的其中一个参数来发送。

    例如我们经常执行的 SET 命令,在命令行中我们输入如下:

    SET key value

    使用 RESP 协议规定的格式:

    *3
    $3
    SET
    $3 # 这里 key 一共三个字节
    key
    $5 # 这里 value 一共五个字节
    value

    这个命令的实际协议值如下:

    "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"

    回复

    Redis 命令会返回多种不同类型的回复。

    通过检查服务器发回数据的第一个字节, 可以确定这个回复是什么类型:

    • 状态回复(status reply)的第一个字节是 "+"
    • 错误回复(error reply)的第一个字节是 "-"
    • 整数回复(integer reply)的第一个字节是 ":"
    • 批量回复(bulk reply)的第一个字节是 "$"
    • 多条批量回复(multi bulk reply)的第一个字节是 "*"

    我们知道redis-cli只能看到最终的执行结果,那是因为redis-cli本身就按照RESP进行结果解析的,所以看不到中间结果,redis-cli.c 源码对命令结果的解析结构如下:

    static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
      sds out = sdsempty();
      switch (r->type) {
              // 处理错误回复
      case REDIS_REPLY_ERROR:
          out = sdscatprintf(out,"(error) %s\n", r->str);
      break;
              // 处理状态回复
      case REDIS_REPLY_STATUS:
          out = sdscat(out,r->str);
          out = sdscat(out,"\n");
      break;
              // 处理整数回复
      case REDIS_REPLY_INTEGER:
          out = sdscatprintf(out,"(integer) %lld\n",r->integer);
      break;
              // 处理字符串回复
      case REDIS_REPLY_STRING:
          /* If you are producing output for the standard output we want
          * a more interesting output with quoted characters and so forth */
          out = sdscatrepr(out,r->str,r->len);
          out = sdscat(out,"\n");
      break;
              // 处理 nil
      case REDIS_REPLY_NIL:
          out = sdscat(out,"(nil)\n");
      break;
              // 处理多回复
      case REDIS_REPLY_ARRAY:
          if (r->elements == 0) {
              out = sdscat(out,"(empty list or set)\n");
          } else {
              unsigned int i, idxlen = 0;
              char _prefixlen[16];
              char _prefixfmt[16];
              sds _prefix;
              sds tmp;
    
       
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三产

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值