hiredis(Synchronous API)
hiredis是一個小型的client端的c庫。它只增加了最小對協議的支持,同時它用一個高級別的printf-alike API為了綁定各種redis命令。除了支持發送和接收命令,它還支持對流的解析。hiredis僅支持binary-safe的redis協議,所以需要用的redis版本>=1.2.0. 這個庫包括多個API, 包括同步API,異步API和返回的解析API等。
安裝hiredis:
1)編譯完redis后,在/users/denver/rsun/test/redis/redis-2.6.10/deps/hiredis目錄下會生成相應的動態鏈接庫libhiredis.so和靜態鏈接庫libhiredis.a,
2)執行make install
會將頭文件和庫文件copy到指定的目錄中:
dcmvrh12% make install
mkdir -p /u1/rsun/test/redis/redis-2.6.10/include/hiredis /u1/rsun/test/redis/redis-2.6.10/lib
cp -a hiredis.h async.h adapters /u1/rsun/test/redis/redis-2.6.10/include/hiredis
cp -a libhiredis.so /u1/rsun/test/redis/redis-2.6.10/lib/libhiredis.so.0.10
cd /u1/rsun/test/redis/redis-2.6.10/lib && ln -sf libhiredis.so.0.10 libhiredis.so.0
cd /u1/rsun/test/redis/redis-2.6.10/lib && ln -sf libhiredis.so.0 libhiredis.so
cp -a libhiredis.a /u1/rsun/test/redis/redis-2.6.10/lib
安裝完就可以使用了。
?
關于hiredis支持的Synchronous API,主要包括以下函數:
redisContext *redisConnect(const char *ip, int port); void *redisCommand(redisContext *c, const char *format, ...); void freeReplyObject(void *reply);1 連接
redisConnect函數用來生成redisContext。該上下文用來存儲connect狀態。redisContext結構有一個整形err字段(非0值)用來保存連接的錯誤狀態。字段errstr用來保存錯誤描述。當通過redisConnect連接redis結束后,可以check err字段來查看連接是否成功。
redisContext *c = redisConnect("127.0.0.1", 6379); if (c != NULL && c->err) {printf("Error: %s\n", c->errstr);//handle error }1) redisContext結構體存儲中存儲錯誤信息,文件描述符fd,寫緩沖區,redisReader類對象指針。
typedef struct redisContext {int err;char errstr[128];int fd;int flags;char *obuf;redisReader *reader; } redisContext;2) redisConnect函數實現連接到一個redis server上。
redisContext *redisConnect(const char *ip, int port) {redisContext *c = redisContextInit();c->flags |= REDIS_BLOCK; //設置連接類型是阻塞的redisContextConnectTcp(c, ip, port, NULL);return c; }? ? a. redisConnect函數用于初始化redisContext結構體指針。
? ? b.redisContextConnectTcp函數的定義位于net.c中
? ? ? ? 根據輸入的ip和port綁定地址,使用TCP連接,通過getaddrinfo函數;
? ? ? ? 創建socket;
? ? ? ? 創建socket屬性信息(阻塞),通過fcntl函數;
? ? ? ? 連接redis server端,通過connect函數;
? ? ? ? 設置socket屬性信息,通過setsockopt函數;
2 發送命令
??有許多方式來發送命令給redis。redisCommand方法和printf相似:
reply = redisCommand(context, "SET foo bar");
可以用%s來表示string類型。
reply = redisCommand(context, "SET foo %s", value);
當需要發送二進制安全的string類型時,需要使用%b,后面跟string類型以及他的長度。
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
redisCommand函數實現:
void *redisCommand(redisContext *c, const char *format, ...) {va_list ap;void *reply = NULL;va_start(ap, format);reply = redisvCommand(c, format, ap);va_end(ap);return reply; } 1)采用不定參數的函數實現 2)調用redisvCommand函數來解析redisvFormatCommand(char **target, const char *format, va_list ap) 解析format字符串,根據format的內容從ap中取相應的數據;__redisAppendCommand(redisContext *c, char *cmd, size_t len) 將格式化的命令寫到輸出緩沖區中。3 返回值
通過redisCommand函數的返回值來查看是否執行成功。當有錯誤發生時,返回值為NULL,同時err字段被標識。一旦context返回錯誤,則該context不能被重用,需要新建一個新的connect。
REDIS_REPLY_STATUS:
返回狀態,狀態字符串被放在reply->str中,狀態字符串長度放在reply->len中。
REDIS_REPLY_ERROR:
返回錯誤
REDIS_REPLY_INTEGER:
返回整形值,該值被reply->integer接收,類型為long long
REDIS_REPLY_NIL:
返回一個nil對象,沒有數據被接收。
REDIS_REPLY_STRING:
返回一個字符串,字符串被放在reply->str中,字符串長度放在reply->len中。
REDIS_REPLY_ARRAY:
多個元素被返回,元素的數量存放在reply->elements中。每個元素的返回值存放在redisReply中。
返回值需要被釋放通過freeReplyObject()函數。
void freeReplyObject(void *reply) 根據reply->type的不同值執行不同的free操作。
4 清空
斷開及清空context,使用下列函數:
void redisFree(redisContext *c);
該函數關閉socket,同時做釋放操作。
根據不同對象,執行不同的free操作。
void redisFree(redisContext *c) {if (c->fd->0)close(c->fd);if (c->obuf != NULL) sdsfree(c->obuf);if (c->reader != NULL) redisReaderFree(c->reader);free(c); }5 發送命令
redisCommandArgv函數用來處理多個命令。
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
argc中存放命令數量;argv數組中存放string數組,argvlen為數組長度。
該函數返回值和redisCommand相同。
函數定義如下:
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {if (redisAppendCommandArgv(c, argc, argv, argvlen) != REDIS_OK) return NULL;return __redisBlockForReply(c); }int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) 調用redisFormatCommandArgv函數解析輸入命令集合 調用__redisAppendCommand函數格式化的命令放到輸出緩沖區中__redisBlockForReply(redisContext *c)命令集合放到緩沖區中e.g.
#include <stdio.h> #include <stdlib.h> #include <string.h>#include "hiredis.h"int main(void) {unsigned int j;redisContext *c;redisReply *reply;struct timeval timeout = { 1, 500000 }; //1.5 secondsc = redisConnectWithTimeout((char*)"127.0.0.2", 6379, timeout);if (c->err) {printf("Connection error: %s\n", c->errstr);exit(1);}reply = redisCommand(c, "PING");printf("PING: %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "SET %s %s", "foo", "hello world");printf("SET: %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "SET %b %b "bar", 3, "hello", 5);printf("SET (binary API): %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "GET foo");printf("GET foo: %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "SET %s %s", "foo", "hello world");printf("SET: %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "SET %b %b", "bar", 3, "hello", 5);printf("SET (binary API): %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "GET foo");printf("GET foo: %s\n", reply->str);freeReplyObject(reply);reply = redisCommand(c, "INCR counter");printf("INCR counter: %lld\n", reply->integer);freeReplyObject(reply);reply = redisCommand(c, "INCR counter");printf("INCR counter: %lld\n", reply->integer);freeReplyObject(reply);reply = redisCommand(c, "DEL mylist");freeReplyObject(reply);for (j=0; j<10; j++) {char buf[64];snprintf(buf, 64, "%d", j);reply = redisCommand(c, "LPUSH mylist element-%s", buf);freeReplyObject(reply);}reply = redisCommand(c, "LRANGE mylist 0 -1");if (reply->type == REDIS_REPLY_ARRAY) {for (j=0; j<reply->elements; j++) {printf("%u) %s\n", j, reply->element[j]->str);}}freeReplyObject(reply);return 0; }result: dcmvrh12% ./example PING: PONG SET: OK SET (binary API): OK GET foo: hello world INCR counter: 9 INCR counter: 10 0) element-9 1) element-8 2) element-7 3) element-6 4) element-5 5) element-4 6) element-3 7) element-2 8) element-1 9) element-0?
總結
以上是生活随笔為你收集整理的hiredis(Synchronous API)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis 使用-hiredis库使用(
- 下一篇: redis的redisvCommand的