Hiredis是一個(gè)Redis的C客戶(hù)端庫(kù)函數(shù),基本實(shí)現(xiàn)了Redis的協(xié)議的最小集。這里對(duì)hiredis的api作基本的介紹以及應(yīng)用,主要參考hiredis的README文件以及相關(guān)源碼。
hiredis的安裝,這個(gè)就不贅述了,很簡(jiǎn)單。
同步API接口的使用
我們的項(xiàng)目中使用的hireds接口都是同步的API,所謂同步意思就是使用阻塞的方式向redis server下發(fā)消息。
接口的主要部分為下面三個(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ù)類(lèi)似。
c 是一個(gè)reidsConnect函數(shù)返回的一個(gè)對(duì)象。
2.2.3返回值
返回值是一個(gè)void類(lèi)型的指針,實(shí)際為指向一個(gè)redisReply類(lèi)型的指針。
redisReply的定義
/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
/*命令執(zhí)行結(jié)果的返回類(lèi)型*/
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é)果的類(lèi)型reply->type,reply 為redisReply* 類(lèi)型。
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)中。
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ù)的類(lèi)型。
c 為redisContext對(duì)象
redisAppendCommandArgv函數(shù)和redisCommandArgv函數(shù)類(lèi)似,參數(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);
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ì)清理連接資源并釋放連接。