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ě)的類代碼框架