Redis C語言客戶端庫hiredis文檔翻譯

Hiredis是redis數據庫一個輕量的C語言客戶端庫。git

之因此輕量是因爲它只是簡單的提供了對redis操做語句支持的接口,並無實現具體的操做語句的功能。但正是因爲這種設計使咱們只要熟悉了通用的redis操做語句就能夠很容易的使用該庫和redis數據庫進行交互。github

除了支持發送命令和接收應答/應答數據,它提供了對應答數據的解析操做。並且這個基於I/O層的數據流解析操做設計考慮到了複用性,能夠對應答數據進行通用的解析操做。redis

Hirides僅僅支持二進制安全的redis協議,因此你只能針對版本號大於等於1.2.0的redis服務端使用。數據庫

庫包含多種API,包括同步命令操做API、異步命令操做API和對應答數據進行解析的API。數組

升級

版本0.9.0是hiredis不少特性一次大的更新。可是對現有代碼進行升級應該不會形成大的問題。升級時,要記住的關鍵一點是大於等於0.9.0的版本是使用redisContext*來保持鏈接狀態,以前的版本只是使用了無狀態的文件描述符。安全

同步API

有幾個API須要介紹異步

redisContext *redisConnect(const char *ip, int port);
void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);socket

鏈接redis數據庫

函數 redisConnect 被用來建立一個 redisContext。這個 context 是hiredis持有的鏈接狀態。redisConnect 結構體有一個整型的 err 變量來標識鏈接錯誤碼,若是鏈接錯誤則爲非零值。變量 errstr 標識鏈接結果的文字描述。更多這方面的信息會在如下Errors章節說明。當你使用 redisConnect 來建立鏈接時應該檢查err變量來判斷是否鏈接正常創建。ide

redisContext *c = redisConnect("127.0.0.1", 6379);
if (c != NULL && c->err) {
printf("Error: %s\n", c->errstr); // handle error }函數

發送命令到redis

有多種方法能夠發送命令到redis。

首先介紹的是redisCommand。此函數相似於printf的使用方式,如

reply = redisCommand(context, "SET foo bar");

相似於printf的s%格式化方式,如

reply = redisCommand(context, "SET foo %s", value);

當你須要發送二進制安全的命令能夠採用%b的格式化方式,同時須要一個字符串指針和size_t類型的字符串長度參數,以下

reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);

在API內部,Hiredis根據不一樣的參數分割命令轉化爲操做redis數據庫的標準命令,你能夠格式化多個參數來構造redis的命令,以下

reply = redisCommand(context, "SET key:%s %s", myid, value);

處理redis應答

當命令被成功執行後redisCommand會有相應的返回值。若是有錯誤發生,返回值爲NULL而且redisReply結構體中的err變量將會被設置成相應的值(請參照Errors章節)。一旦有錯誤發生context不能被重用而且你須要創建一個新的鏈接

redisCommand執行後返回值類型爲redisReply。經過redisReply結構體中的type變量能夠肯定命令執行的狀況。

  • REDIS_REPLY_STATUS:

    • 返回執行結果爲狀態的命令。好比set命令的返回值的類型是REDIS_REPLY_STATUS,而後只有當返回信息是"OK"時,才表示該命令執行成功。能夠經過reply->str獲得文字信息,經過reply->len獲得信息長度。

  • REDIS_REPLY_ERROR:

    • 返回錯誤。錯誤信息能夠經過reply->str獲得文字信息,經過reply->len獲得信息長度。

  • REDIS_REPLY_INTEGER:

    • 返回整型標識。能夠經過reply->integer變量獲得類型爲long long的值。

  • REDIS_REPLY_NIL:

    • 返回nil對象,說明不存在要訪問的數據。

  • REDIS_REPLY_STRING:

    • 返回字符串標識。能夠經過reply->str獲得具體值,經過reply->len獲得信息長度。

  • REDIS_REPLY_ARRAY:

    • 返回數據集標識。數據集中元素的數目能夠經過reply->elements得到,每一個元素是個redisReply對象,元素值能夠經過reply->element[..index..].*形式得到,用在獲取多個數據結果的操做。

執行完命令調用後應該經過freeReplyObject()釋放redisReply,對於嵌套對象(好比數組)要注意,並不須要嵌套進行釋放,這樣是有害的會形成內存破壞。

Important:hiredis當前版本 (0.10.0)當使用異步API時會本身釋放replies對象。這意味着你使用異步API時並不須要主動調用freeReplyObject 。relpy對象當回調返回時將會被自動釋放。可是這種行爲也許會在未來的版本中改變,因此升級時請密切關注升級日誌。

清理鏈接資源

斷開鏈接而且釋放context使用如下函數

void redisFree(redisContext *c);

此函數立馬關閉socket而且釋放建立context時分配的資源。

發送多個命令參數

和redisCommand函數類似,redisCommandArgv函數能夠用於傳輸多個命令參數。函數原型爲

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

,相似於 lpush, del key1 key2..., zadd key score1 member1 score2 member2...這類命令, 其中 argc是傳遞參數的個數, argv主要用於傳遞的string的value, 而argvlen 是每一個string的size。

此函數返回值與redisCommand類似。參考https://gist.github.com/dspezia/1455082

管線(Pipelining)

爲了搞清楚Hiredis在阻塞鏈接下的管線操做,須要理解其內部執行過程。

當任何相似於redisCommand的函數被調用,Hiredis首先將命令格式化爲redis支持的命令協議。被格式化後的命令被放入context的輸出緩衝區,這個緩衝區是動態的,因此它能夠容納任意數量的命令。在命令進入輸出緩衝區後,redisGetReply 函數被調用。這個函數有如下兩種執行方式:

  1. 輸入緩衝區非空:

    • 從輸入緩衝區中嘗試解析單獨的reply對象而且返回reply

    • 若是沒有reply能被解析,執行步驟2

  2. 輸入緩衝區爲空:

    • 將整個輸出緩衝區寫入socket

    • 從socket中讀取數據直到有一個reply能被解析

Hiredis爲了有效利用socket還提供了redisGetReply的接口。對於管線命令,須要完成的惟一事情就是填充輸出緩衝區。有兩個函數被用於執行此操做,這兩個函數基本與redisCommand函數功能相似,可是他們不返回reply

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

當這兩個函數被一次或屢次調用時,經過redisGetReply依次返回replies。redisGetReply的返回值要麼是REDISOK或是REDISERR,REDIS_ERR意味着得到reply發生了錯誤,想要獲得具體的錯誤緣由能夠經過err變量來獲取。

如下經過一個簡單例子說明管線的使用:

redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);

redisGetReply這個API也能夠被用來實現阻塞的訂閱模式

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

Errors

若是某些函數(如redisConnect, redisCommand(調用不成功,函數返回值爲NULL或者REDIS_ERR,此時context結構體中的err成員爲非零值,可能爲如下幾種常量

  • REDIS_ERR_IO:當建立鏈接時(試着寫socket或者讀socket)發生的I/O錯誤。若是你在代碼中包含了errno.h頭文件,你便能獲得準確的錯誤碼。

  • REDIS_ERR_EOF:redis服務端已經關閉了此鏈接。

  • REDIS_ERR_PROTOCOL:服務端解析協議時發生了錯誤。

  • REDIS_ERR_OTHER:其餘錯誤。目前僅僅表示沒法解析目標主機名的錯誤。

在錯誤狀況下,能夠經過context結構體中的errstr成員獲得錯誤的確切描述。

異步API

Hiredis自帶的異步API很容易和一些基於事件的庫結合使用。好比和libev、ibevent的結合使用。

鏈接

函數redisAsyncConnect被用來和redis創建非阻塞鏈接。它返回redisAsyncContext的結構體,結構體的err成員用來檢查在建立鏈接的過程當中是否發生了錯誤。由於建立的是非阻塞的鏈接,內核並不能立馬返回一個鏈接指定主機的結果。

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err)
{
printf("Error: %s\n", c->errstr);
// handle error
}

異步Context可設置一個響應斷開鏈接事件的回調函數,當鏈接斷開時會相應執行。回調函數的原型爲

void(const redisAsyncContext *c, int status);

在斷開鏈接的狀況下,當鏈接是由用戶本身斷開的status參數爲REDISOK,若是出現了其餘錯誤status參數爲REDISERR,當錯誤時經過err成員能夠獲得準確的錯誤碼。

當回調執行完畢後context對象會本身釋放資源。此事件的回調函數給你建立一個新鏈接提供了便利。

一個context對象僅能設置一次斷開鏈接的回調,若是再進行下一次設置將會返回REDIS_ERR。設置斷開鏈接回調函數的原型爲:

int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);

發送操做命令而且響應回調事件

在異步的狀況下,redis的操做指令將會被自動加入事件循環隊列。因爲發送命令執行的過程是異步的,當命令執行完畢後將會調用相應的回調函數。回調函數的原型爲

void(redisAsyncContext *c, void *reply, void *privdata);

privdata參數是由調用者本身定義的數據類型。

如下是進行異步命令操做的函數:

int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,const char *format, ...);

int redisAsyncCommandArgv( redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);

命令的使用方式和上面所講的同步接口相似。執行成功返回REDIS_OK,不然返回REDIS_ERR。好比鏈接已經關閉的狀況下再使用redisAsyncCommand向此鏈接執行命令就會返回REDIS_ERR。

回調執行完畢後若是reply不爲空,回調執行完畢後將自動對reply的資源進行回收。

當context發生錯誤時回調獲得的reply將爲空。

斷開鏈接

一個異步的鏈接能夠經過下面這個函數終止

void redisAsyncDisconnect(redisAsyncContext *ac);

當這個函數被調用時,鏈接並不會被當即關閉,而是等待全部這個鏈接的異步命令操做執行完畢,而且回調事件已經執行完畢後才關閉此鏈接,這時在響應關閉鏈接事件的回調函數中獲得的狀態爲REDIS_OK,此鏈接的資源也將會被自動回收。

將其掛接到事件庫X

在context對象被建立後進行不多的幾步操做就能夠進行掛接。參看目錄adapters/下是如何掛接到libev 和 libevent下的。

應答解析API

Hiredis自帶的答覆解析API ,能夠很容易與更高層次的語言進行綁定。 TODO:

相關文章
相關標籤/搜索