Hiredis是一個Redis的C客戶端庫函數(shù),基本實現(xiàn)了Redis的協(xié)議的最小集。這里對hiredis的api作基本的介紹以及應(yīng)用,主要參考hiredis的README文件以及相關(guān)源碼。
hiredis的安裝,這個就不贅述了懦趋,很簡單。
同步API接口的使用
我們的項目中使用的hireds接口都是同步的API疹味,所謂同步意思就是使用阻塞的方式向redis server下發(fā)消息仅叫。
接口的主要部分為下面三個部分,下面分別介紹糙捺。
/**連接數(shù)據(jù)庫*/
redisContext *redisConnect(const char *ip, int port);
/**發(fā)送命令請求*/
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ù)庫
2.1.1函數(shù)原型:
redisContext *redisConnect(const char *ip, int port);
2.1.2參數(shù)說明:
port:為redis數(shù)據(jù)監(jiān)聽的端口號诫咱,redis默認監(jiān)聽的端口號為6379
ip:為redis數(shù)據(jù)庫的IP地址,可以是遠程的洪灯,也可以是本地的127.0.0.1
2.1.3返回值
返回值是一個指向redisContext對象遂跟,可以不用了解這個對象的具體組成部分,只需要知道怎么使用就可以了婴渡。下面是其定義幻锁。
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");
}
}
這個redisContext不是一個線程安全的對象,也就是說边臼,多個線程同時訪問這一個對象可能會出現(xiàn)問題哄尔。
2.2 發(fā)送需要執(zhí)行的命令
2.2.1發(fā)送命令函數(shù)原型
void *redisCommand(redisContext *c, const char *format, ...);
2.2.2參數(shù)說明
這個函數(shù)是一個帶有不定參數(shù)的∧ⅲ可以按著format格式給出對應(yīng)的參數(shù)岭接,這就和printf函數(shù)類似富拗。
c 是一個reidsConnect函數(shù)返回的一個對象。
2.2.3返回值
返回值是一個void類型的指針鸣戴,實際為指向一個redisReply類型的指針啃沪。
redisReply的定義
/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
/*命令執(zhí)行結(jié)果的返回類型*/
int type; /* REDIS_REPLY_* */
/*存儲執(zhí)行結(jié)果返回為整數(shù)*/
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
/*字符串值的長度*/
size_t len; /* Length of string */
/*存儲命令執(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 */
/*存儲執(zhí)行結(jié)果返回是數(shù)組*/
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
返回結(jié)果的類型reply->type,reply 為redisReply* 類型。
REDIS_REPLY_STRING == 1:返回值是字符串,字符串儲存在redis->str當中,字符串長度為redis->len窄锅。
REDIS_REPLY_ARRAY == 2:返回值是數(shù)組创千,數(shù)組大小存在redis->elements里面,數(shù)組值存儲在redis->element[i]里面入偷。數(shù)組里面存儲的是指向redisReply的指針追驴,數(shù)組里面的返回值可以通過redis->element[i]->str來訪問,數(shù)組的結(jié)果里全是type==REDIS_REPLY_STRING的redisReply對象指針疏之。
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丙曙,存儲在str當中 reply->str == "OK"。
REDIS_REPLY_ERROR ==6 :命令執(zhí)行錯誤,錯誤信息存放在 reply->str當中其骄。
redisCommandArgv函數(shù)
函數(shù)原型
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
參數(shù)說明
argvlen這個數(shù)組存儲了命令參數(shù)中亏镰,每一個參數(shù)的長度,包含命令本身年栓,比如 set foo bar 則argvlen ={3,3,3},如果argvlen為空,那么這個函數(shù)內(nèi)部會自動調(diào)用strlen函數(shù)對每個參數(shù)進行求長度薄霜。
argv 存放每個命令參數(shù)的指針某抓,argv={"set","foo","bar"}
argc 存放命令參數(shù)的個數(shù)上面的例子中argc=3
c 為redisContext對象。
為每一個參數(shù)指定長度惰瓜,可以是二進制安全的函數(shù)否副。函數(shù)會按著長度來決定字符串的終止,而不是'\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
會得到321并不會得到和hvalue一樣的值"3210"崎坊,因為在hset命令中指定了長度备禀,只會讀取前面的三個字符。
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ù)說明:
redisAppendCommand函數(shù)和redisCommand函數(shù)參數(shù)一致奈揍,format可以指定特定參數(shù)的類型曲尸。
c 為redisContext對象
redisAppendCommandArgv函數(shù)和redisCommandArgv函數(shù)類似,參數(shù)含義也相同男翰。
redisGetReply函數(shù)用來獲得執(zhí)行的結(jié)果的一條返回另患,并存儲在reply所指的對象當中。成功返回REDIS_OK,否則返回REIDS_ERR蛾绎。多條命令的一次性返回結(jié)果都存放在redisContext里面昆箕。
所不同的是鸦列,這個兩個命令的結(jié)果。這兩個函數(shù)是把多個命令存放在緩沖區(qū)內(nèi)鹏倘,然后一起發(fā)送給redis服務(wù)器薯嗤,一次執(zhí)行∠吮茫可以通過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ù)說明
freeReplyObject函數(shù)中reply 實際為指向redisReply結(jié)構(gòu)體的指針,可能是redisCommand的返回值夕吻,后續(xù)可以看到以也能是管道命令執(zhí)行結(jié)果的返回值诲锹。
redisFree函數(shù)中c實際為指向redisContext對象,這個函數(shù)會清理連接資源并釋放連接涉馅。