hiredis的使用

hiredis的使用

標(biāo)簽(空格分隔): Linux

作業(yè)部落地址:https://www.zybuluo.com/LIUHUAN/note/364481


1.hiredis的安裝,這個(gè)就不介紹了。

2.同步API接口的使用

接口的主要部分為下面三個(gè)部分,下面分別介紹。

/**連接數(shù)據(jù)庫(kù)*/
redisContext *redisConnect(const char *ip, int port);
/**發(fā)送命令請(qǐng)求*/
void *redisCommand(redisContext *c, const char *format, ...);
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
/*釋放資源*/
void freeReplyObject(void *reply);
void redisFree(redisContext *c);

2.1連接redis數(shù)據(jù)庫(kù)

2.1.1函數(shù)原型:
redisContext *redisConnect(const char *ip, int port);
2.1.2參數(shù)說(shuō)明:
  • port:為redis數(shù)據(jù)監(jiān)聽(tīng)的端口號(hào),redis默認(rèn)監(jiān)聽(tīng)的端口號(hào)為6379
  • ip:為redis數(shù)據(jù)庫(kù)的IP地址,可以是遠(yuǎn)程的,也可以是本地的127.0.0.1
2.1.3返回值
  • 返回值是一個(gè)指向redisContext對(duì)象,可以不用了解這個(gè)對(duì)象的具體組成部分,只需要知道怎么使用就可以了。下面是其定義。
typedef struct redisContext {
    int err; /* Error flags, 0 when there is no error */
    char errstr[128]; /* String representation of error when applicable */
    int fd;
    int flags;
    char *obuf; /* Write buffer */
    redisReader *reader; /* Protocol reader */
    enum redisConnectionType connection_type;
    struct timeval *timeout;
    struct {
        char *host;
        char *source_addr;
        int port;
    } tcp;
    struct {
        char *path;
    } unix_sock;
} redisContext;
2.1.4 使用例子
redisContext *c = redisConnect("127.0.0.1", 6379);
if (c == NULL || c->err) {
    if (c) {
        printf("Error: %s\n", c->errstr);
        // handle error
    } else {
        printf("Can't allocate redis context\n");
    }
}
  • 這個(gè)redisContext不是一個(gè)線程安全的對(duì)象,也就是說(shuō),多個(gè)線程同時(shí)訪問(wèn)這一個(gè)對(duì)象可能會(huì)出現(xiàn)問(wèn)題。

2.2.發(fā)送需要執(zhí)行的命令

2.2.1發(fā)送命令函數(shù)原型
void *redisCommand(redisContext *c, const char *format, ...);
2.2.2參數(shù)說(shuō)明
  • 這個(gè)函數(shù)是一個(gè)帶有不定參數(shù)的??梢园粗鴉ormat格式給出對(duì)應(yīng)的參數(shù),這就和printf函數(shù)類似。
  • c 是一個(gè)reidsConnect函數(shù)返回的一個(gè)對(duì)象。
2.2.3返回值
  • 返回值是一個(gè)void類型的指針,實(shí)際為指向一個(gè)redisReply類型的指針。
  • redisReply的定義
/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
    /*命令執(zhí)行結(jié)果的返回類型*/
    int type; /* REDIS_REPLY_* */
    /*存儲(chǔ)執(zhí)行結(jié)果返回為整數(shù)*/
    long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
    /*字符串值的長(zhǎng)度*/
    size_t len; /* Length of string */
    /*存儲(chǔ)命令執(zhí)行結(jié)果返回是字符串*/
    char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
    /*返回結(jié)果是數(shù)組的大小*/
    size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
    /*存儲(chǔ)執(zhí)行結(jié)果返回是數(shù)組*/
    struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;

返回結(jié)果的類型reply->type,reply 為redisReply* 類型。

  • REDIS_REPLY_STRING == 1:返回值是字符串,字符串儲(chǔ)存在redis->str當(dāng)中,字符串長(zhǎng)度為redis->len。
  • REDIS_REPLY_ARRAY == 2:返回值是數(shù)組,數(shù)組大小存在redis->elements里面,數(shù)組值存儲(chǔ)在redis->element[i]里面。數(shù)組里面存儲(chǔ)的是指向redisReply的指針,數(shù)組里面的返回值可以通過(guò)redis->element[i]->str來(lái)訪問(wèn),數(shù)組的結(jié)果里全是type==REDIS_REPLY_STRING的redisReply對(duì)象指針。
  • REDIS_REPLY_INTEGER == 3:返回值為整數(shù) long long。
  • REDIS_REPLY_NIL==4:返回值為空表示執(zhí)行結(jié)果為空。
  • REDIS_REPLY_STATUS ==5:返回命令執(zhí)行的狀態(tài),比如set foo bar 返回的狀態(tài)為OK,存儲(chǔ)在str當(dāng)中 reply->str == "OK"。
  • REDIS_REPLY_ERROR ==6 :命令執(zhí)行錯(cuò)誤,錯(cuò)誤信息存放在 reply->str當(dāng)中。

返回結(jié)果示例:

  • set key value : 返回 string reply->str == "OK"。
  • hset key hkey value:返回 integer reply->integer == 1。
  • hdel key hkey:返回 integer reply->integer ==1。
  • sadd set member:返回 integer reply->integer ==1。
  • sismember setkey member:返回 integer reply->integer ==1。
  • smembers setkey:返回 array reply->element[i]->str為返回結(jié)果值。
redisCommandArgv函數(shù)

函數(shù)原型

void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

參數(shù)說(shuō)明

  • argvlen這個(gè)數(shù)組存儲(chǔ)了命令參數(shù)中,每一個(gè)參數(shù)的長(zhǎng)度,包含命令本身,比如 set foo bar 則argvlen ={3,3,3},如果argvlen為空,那么這個(gè)函數(shù)內(nèi)部會(huì)自動(dòng)調(diào)用strlen函數(shù)對(duì)每個(gè)參數(shù)進(jìn)行求長(zhǎng)度。
  • argv 存放每個(gè)命令參數(shù)的指針,argv={"set","foo","bar"}
  • argc 存放命令參數(shù)的個(gè)數(shù)上面的例子中argc=3
  • c 為redisContext對(duì)象。
  • 為每一個(gè)參數(shù)指定長(zhǎng)度,可以是二進(jìn)制安全的函數(shù)。函數(shù)會(huì)按著長(zhǎng)度來(lái)決定字符串的終止,而不是'\0'.
char hkey[] = "123456";
char hset[] = "hset";
char key[] = "testkey";
char hvalue[] = "3210";
int argc = 4;
char *argv[] = {hset,key,hkey,hvalue};
size_t argvlen[] = {4,6,4,3};
redisCommandArgv(context,argc,argv,argvlen);

> hgetall testkey
會(huì)得到321并不會(huì)得到和hvalue一樣的值"3210",因?yàn)樵趆set命令中指定了長(zhǎng)度,只會(huì)讀取前面的三個(gè)字符。

redisAppendCommand*函數(shù)支持管道命令

函數(shù)原型:

void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
int redisGetReply(redisContext *context,redisReply** reply);

參數(shù)說(shuō)明:

  • redisAppendCommand函數(shù)和redisCommand函數(shù)參數(shù)一致,format可以指定特定參數(shù)的類型。
  • c 為redisContext對(duì)象
  • redisAppendCommandArgv函數(shù)和redisCommandArgv函數(shù)類似,參數(shù)含義也相同。
  • redisGetReply函數(shù)用來(lái)獲得執(zhí)行的結(jié)果的一條返回,并存儲(chǔ)在reply所指的對(duì)象當(dāng)中。成功返回REDIS_OK,否則返回REIDS_ERR。多條命令的一次性返回結(jié)果都存放在redisContext里面。
  • 所不同的是,這個(gè)兩個(gè)命令的結(jié)果。這兩個(gè)函數(shù)是把多個(gè)命令存放在緩沖區(qū)內(nèi),然后一起發(fā)送給redis服務(wù)器,一次執(zhí)行。可以通過(guò)redisGetReply函數(shù)從
    redisContext中取出返回的結(jié)果。

使用例子:

redisReply *reply;
/*添加命令set */
redisAppendCommand(context,"SET foo bar");
/*添加命令get */
redisAppendCommand(context,"GET foo");
/*獲取set命令結(jié)果*/
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
/*獲取get命令結(jié)果*/
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);

也可以使用這個(gè)功能來(lái)實(shí)現(xiàn)發(fā)布訂閱功能。

reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,&reply) == REDIS_OK) {
    // consume message
    freeReplyObject(reply);
}

所有的返回結(jié)果都需要釋放資源調(diào)用freeReplyObject函數(shù)。這個(gè)函數(shù)會(huì)遞歸的釋放數(shù)組中的資源,不需要手動(dòng)釋放數(shù)組資源。

2.3釋放資源

2.3.1函數(shù)原型
void freeReplyObject(void *reply);
void redisFree(redisContext *c);
2.3.2參數(shù)說(shuō)明
  • freeReplyObject函數(shù)中reply 實(shí)際為指向redisReply結(jié)構(gòu)體的指針,可能是redisCommand的返回值,后續(xù)可以看到以也能是管道命令執(zhí)行結(jié)果的返回值。
  • redisFree函數(shù)中c實(shí)際為指向redisContext對(duì)象,這個(gè)函數(shù)會(huì)清理連接資源并釋放連接。

如果使用c++來(lái)操作redis數(shù)據(jù)庫(kù),建議寫(xiě)一個(gè)類對(duì)這些C的接口進(jìn)行封裝,符合自己的邏輯。下面是一個(gè)可能使用方案。


class Redis
{
    public:
        redisContext* context;
        Redis(const char * ip="127.0.0.1",int port=6379){
            this->context = redisConnect(ip,port);
            if(this->context == NULL || context->err){
                if(context){
                    printf("Error: %s\n",context->errstr);
                    exit(-1);
                }else{
                    printf("can not allocate redis context\n");
                    exit(-1);
                }
            }
        }
        
        string hget(const char* key,const  char* hkey){
            const char* argv[3];
            size_t argvlen[3];
            argv[0] = "HGET";
            argvlen[0] = 4;
            argv[1] = key;
            argvlen[1] = strlen(key);
            argv[2] = hkey;
            argvlen[2] = strlen(hkey);
            redisReply* reply =(redisReply*) redisCommandArgv(this->context, 3, argv, argvlen);
            string value;
            if(reply->type != REDIS_REPLY_NIL){
                value = string(reply->str,reply->str + reply->len);
            }
            freeReplyObject(reply);
            return value;
        }
        int hset(const char* key, const char* hkey, const char* value){
            redisReply* reply =(redisReply*) redisCommand(this->context, "HSET %s %s %s",key,hkey, value);
            freeReplyObject(reply);
            return 1;
        }
        int hset(const char* key,const char* hkey,const char* hvalue, size_t hvaluelen){
            const char* argv[4];
            size_t argvlen[4];
            argv[0] = "HSET";
            argvlen[0] = 4;
            argv[1] = key;
            argvlen[1] = strlen(key);
            argv[2] = hkey;
            argvlen[2] = strlen(hkey);
            argv[3] = hvalue;
            argvlen[3] = hvaluelen;
            redisReply * reply =(redisReply*) redisCommandArgv(this->context, 4, argv, argvlen);
            freeReplyObject(reply);
            return 1;
        }
        /**delete key*/?
        int del(const char* key){
            int res = 0;4
            redisReply* reply = (redisReply*)redisCommand(this->context, "DEL %s", key);
            if(reply->type == REDIS_REPLY_INTEGER){
                if(reply->integer == 1L)
                    res = 1;
            }
            freeReplyObject(reply);
            return res;
        }

        /*if Key ID exists*/
        int existsKey(const char* ID){
            redisReply * reply = (redisReply*)redisCommand(this->context,"exists %s",ID);
            int res = 0;
            if(reply->type == REDIS_REPLY_INTEGER){
                if(reply->integer == 1L)
                    res  = 1;
            }
            freeReplyObject(reply);
            return res;
        }
        virtual ~Redis(){
            redisFree(this->context);
        }
    protected:
    private:
};

7.參考內(nèi)容

  • hiredis 的github網(wǎng)站
  • 感謝小w寫(xiě)的類代碼框架
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容