虚位以待(AD)
虚位以待(AD)
首页 > 数据库 > DB2数据库 > redisclientprotocol实现

redisclientprotocol实现
类别:DB2数据库   作者:码皇   来源:一头汗的专栏     点击:

在官网中http: redis io clients有许多已经实现好的redis client;有需要可以参考一下。其实前一篇http: blog csdn net yitouhan article details 46612925 redis client protocol 解析,我已经对RESP做

 

下面是解析RESP的所有函数,其中对外函数是RedisProtocol::Decode:

https://github.com/XJM2013/GameEngine/blob/master/lib/src/redis/redisprotocol.cpp

 

    static unsigned int EndLine(const char *buf, unsigned int len);
    static int ReadNumber(const char *buf, unsigned int len);
    static char _ReadString(const char *buf, unsigned int left_len, int &read_len, RedisData **data);
    static int ReadMessage(char type, const char *buf, unsigned int len, RedisBulkData **bulk_data);
    static int ReadInteger(const char *buf, unsigned int len, RedisBulkData **bulk_data);
    static int ReadString(const char *buf, unsigned int len, RedisBulkData **bulk_data);
    static int ReadArray(const char *buf, unsigned int left_len, RedisBulkData **bulk_data);
    /* :1rn 前缀 + 结果 + 结束 最少也要有4个字节*/int RedisProtocol::Decode(const char *buf, unsigned int len, RedisBulkData **bulk_data){
    if (len < 4) {
    return OPR_MORE_DATA;
    }
    switch (buf[0]) {
    case '
    +'
    : return ReadMessage(REPLY_TYPE_OK, buf + 1, len - 1, bulk_data);
    case '
    -'
    : return ReadMessage(REPLY_TYPE_ERROR, buf + 1, len - 1, bulk_data);
    case '
    :'
    : return ReadInteger(buf + 1, len - 1, bulk_data);
    case '
    $'
    : return ReadString(buf + 1, len - 1, bulk_data);
    case '
    *'
    : return ReadArray(buf + 1, len - 1, bulk_data);
    default: return OPR_DATA_INVALID;
    }
    return OPR_DATA_INVALID;
    }
从上面的代码来看,可以看出,代码的结构相当清晰、简洁;而且这代码的功能只是对协议的处理,不包含网络模块和其它更复杂的封装等处理,不需要做额外的辨别阅读。对于学习协议者,个人觉得还是一个不错的选择。代码中我有做一些内存池的功能,不想使用的,可以用new/delete 或者 malloc/free代替。
下面我基于前一篇文章说的5个例子,分别作为测试例子:

https://github.com/XJM2013/GameEngine/blob/master/Test/testredis.h

 

    #ifndef TEST_REDIS_H#define TEST_REDIS_H#include #include "lib/include/redis/redisprotocol.h"namespace TestRedis{
    void ShowBulkData(RedisBulkData *data) {
    std::list::iterator itr = data->data_list.begin();
    for (;
    itr != data->data_list.end();
    ++itr) {
    printf("type = %dn", (*itr)->type);
    switch ((*itr)->type) {
    case RedisProtocol::REPLY_TYPE_INTEGER: case RedisProtocol::REPLY_TYPE_STRING_ERROR: case RedisProtocol::REPLY_TYPE_ARRAY_ERROR: printf("data = %dn", *(int *)(*itr)->data);
    break;
    default: printf("data = %.*sn", (*itr)->len, (*itr)->data);
    break;
    }
    }
    }
    void Decode(char *reply) {
    RedisBulkData *data = NULL;
    if (RedisProtocol::Decode(reply, strlen(reply), &data) <= RedisProtocol::OPR_MORE_DATA) {
    return;
    }
    ShowBulkData(data);
    delete data;
    }
    // 短字符串 void Test1() {
    char *reply = "+OKrn";
    Decode(reply);
    }
    // 错误 void Test2() {
    char *reply = "-ERR unknown command '
    seet'
    rn";
    Decode(reply);
    }
    // 整数 void Test3() {
    char *reply = ":11rn";
    Decode(reply);
    }
    // 长字符串 void Test4() {
    char *reply1 = "$3rncatrn";
    printf("reply1:n");
    Decode(reply1);
    char *reply2 = "$-1rn";
    printf("reply2:n");
    Decode(reply2);
    }
    // 数组 void Test5() {
    char *reply1 = "*2rn$3rncatrn$2rn11rn";
    printf("reply1:n");
    Decode(reply1);
    char *reply2 = "*2rn$4rnfishrn$-1rn";
    printf("reply2:n");
    Decode(reply2);
    char *reply3 = "*-1rn";
    printf("reply3:n");
    Decode(reply3);
    }
    }
    #endif
下面输出一下Test5()的结果:

 

协议解析总结:

1、从C/C++的角度来看,序列化保存数据,解析更快。

例如将1000条数据序列化成1条数据:

从分配空间的角度来看,1000条数据需要分配1000次空间,1条数据需要分配1次空间。

从解析的角度来看,RESP的结构是LV结构,也就是长度-值(length-value)结构,其不需要标志类型(T,type),因为它的类型都是字符串类型。而序列化实现可以是TV和TLV结构的结合。因此C/C++里面类型与长度是一一对应的,整型就是4个字节等等;对于字符串则使用TLV结构。这里大致只需要将RESP的L与序列化的T做一个对比。一个需要匹配"rn",并将字符串转化成数字,一个则只需要读取第一字节则可以判断数据长度。

2、set key valrn,当val很长,例如10k字节长,server 要匹配10k次才能匹配到rn,而且val中不允许出现rn否则会出错。

相关热词搜索: redisclientprotocol实现