1. 程式人生 > >hiredis(一個輕量級redis的c客戶端)

hiredis(一個輕量級redis的c客戶端)

1.簡單介紹

hiredis是一個輕量級的訪問redis資料庫的c客戶端。

它是輕量級的不僅僅是因為它僅僅提供對協議的最小支援,而且它使用了一個高級別的極度類似於printf的api使它的級別遠高於其最小程式碼庫和缺乏繫結的redis命令。簡而言之,就是更靈活。

除了支援傳送命令和接受命令,它還有一個與io層分離的回覆解析器。它是一個簡單靈活的流解析器,可以用於更高級別的語言繫結以實現有效的回覆解析。

 hiredis僅僅支援二進位制安全的redsi協議,因此你可以使用它在redis的版本的大於1.2.0.

 hiredis提供多套api,包括同步的api,非同步api,回覆解析的api.

2.同步api

要使用同步api,僅僅需要學會使用幾個函式。

redisContext *redisConnect(const char *ip, int port);      voidredisFree(redisContext *c);

void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);

1)redisConnect返回一個redisContext的結構體, 這個結構用於儲存連線狀態。這個結構體包含一個integer型別的err資料成員,這個成員非0,當連線處於一個錯誤狀態的時候,另一個string的資料成員指出具體的錯誤原因。在呼叫redisConnect之後應該檢查err以測試是否連線成功。

2)向redis傳送命令有好幾種方式。

第一種方式:

redisCommand,提供了一種類似於printf的形式去傳送命令。第一個引數是redisConnect的返回值。

最簡單的形式:

reply = redisConnect(context, "set foo bar");

使用%s插入字串的形式:

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

傳送二進位制字串的形式,但同時需要指出字串的長度:

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

傳送多個分離的字串的形式:

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

類似於命令列的形式:

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

第四個引數是每個引數字串的長度

回覆:

當命令成功執行時,redisCommand的返回值會保留一個回覆。發生錯誤時,返回值為NULL,上下文中的err欄位將被設定(請參閱錯誤部分)。一旦錯誤返回,上下文不能被重用,你應該建立一個新的連線。
標準回覆redisCommand的型別是redisReply。 redisReply中的型別欄位應該用於測試收到的回覆型別:
REDIS_REPLY_STATUS:
該命令回覆了狀態回覆。狀態字串可以使用reply-> str來訪問。該字串的長度可以使用reply-> len來訪問。
REDIS_REPLY_ERROR:
該命令回覆了一個錯誤。錯誤字串可以與REDIS_REPLY_STATUS相同訪問。
REDIS_REPLY_INTEGER:
該命令用一個整數來回答。整數值可以使用long long型別的reply-> integer欄位來訪問。
REDIS_REPLY_NIL:
該命令回答了一個零物件。沒有要訪問的資料。
REDIS_REPLY_STRING:
批量(字串)回覆。答覆的值可以使用reply-> str來訪問。該字串的長度可以使用reply-> len來訪問。
REDIS_REPLY_ARRAY:

多批量回復。多批量答覆中的元素數量儲存在reply->元素中。多批量回復中的每個元素也是一個redisReply物件,可以通過reply-> element [.. index ..]進行訪問。 Redis可能會迴應巢狀陣列,但這完全受支援。

應使用freeReplyObject()函式釋放回復。 請注意,這個函式將負責釋放包含在陣列和巢狀陣列中的子回覆物件,所以使用者不需要釋放子回覆(它實際上是有害的並且會損壞記憶體)。

3)將命令序列化

當redisCommand系列中的任何函式被呼叫時,Hiredis首先根據Redis協議格式化該命令。然後將格式化的命令放入redisContext的輸出緩衝區中。這個輸出緩衝區是動態的,所以它可以容納任意數量的命令。將命令放入輸出緩衝區後,呼叫redisGetReply。這個函式有以下兩個執行路徑:
        輸入緩衝區非空:
            嘗試解析來自輸入緩衝區的單個回覆並將其返回
            如果沒有答覆可以解析,相當於輸入緩衝區為空的情況
        輸入緩衝區為空:
            將整個輸出緩衝區寫入套接字
            從套接字讀取,直到可以解析單個回覆

對於序列化命令,唯一需要做的事情是填充輸出緩衝區。由於這個原因,除了不返回一個回覆之外,可以使用兩個與redisCommand系列相同的命令,然後我們用redisGetReply獲取命令的返回結果。

    void redisAppendCommand(redisContext *c, const char *format, ...);

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

官方文件如上描述,但其實原始碼中這兩個命令的返回值是int。

使用方法如下:

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);

4)error

當函式呼叫不成功時,根據函式返回NULL或REDIS_ERR。 context中的err欄位將為非零值,並設定為以下常量之一:
REDIS_ERR_IO:建立連線時發生I / O錯誤,嘗試寫入套接字或從套接字讀取。 如果您在應用程式中包含errno.h,則可以使用全域性errno變數來找出錯誤。
REDIS_ERR_EOF:伺服器關閉導致空讀的連線。
REDIS_ERR_PROTOCOL:解析協議時發生錯誤。
REDIS_ERR_OTHER:任何其他錯誤。 目前,只有在指定的主機名連線時才能使用它。
在任何情況下,context中的errstr欄位都將設定為儲存錯誤的字串表示形式

4.程式碼

編譯的時候切記加上動態連結庫。可以使用pkg-config --cflags --libs hiredis顯示如何加。

/*************************************************************************
 > File Name: main.cpp
 > Author: aben
 > Mail: [email protected] 
> Created Time: Sat 19 May 2018 08:52:02 PM PDT
 ************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <hiredis/hiredis.h>


using namespace std;


void prase(redisReply *reply)
{
int seq = 0;
if (NULL == reply) {
printf("redisReply id NULL\n");
return;
}
switch (reply->type) 
{
case REDIS_REPLY_STATUS:
printf("REDIS_REPLY_STATUS:%s\n", reply->str);
break;
case REDIS_REPLY_ERROR:
printf("REDIS_REPLY_ERROR:%s\n", reply->str);
break;
case REDIS_REPLY_INTEGER:
printf("REDIS_REPLY_INTEGER:%lld\n", reply->integer);
break;
case REDIS_REPLY_NIL:
printf("REDIS_REPLY_NIL:NULL\n");
break;
case REDIS_REPLY_STRING:
printf("REDIS_REPLY_STRING:%s\n", reply->str);
break;
case REDIS_REPLY_ARRAY:
printf("REDIS_REPLY_ARRAY\n");
while(seq < reply->elements) {
printf("REDIS_REPLY_STRING:%s   ", reply->element[seq]->str);
if (seq++ % 3 == 0) {
printf("\n");
}
}
printf("\n");
break;
default:
break;
}
freeReplyObject(reply);
}


int main()
{
redisContext *c = redisConnect("127.0.0.1", 6379);
if (c == NULL || c->err) {
if (c) {
printf("Error:%s\n", c->errstr);
} else {
printf("conn't allocate redis context\n");
}
exit(-1);
}
printf("redis connect return %d:%s\n", c->err, c->errstr);


 redisReply *reply = (redisReply*)redisCommand(c, "set company noahwm");
prase(reply);
 reply = (redisReply*)redisCommand(c, "set phone 17621079235");
prase(reply);
 reply = (redisReply*)redisCommand(c, "keys *");
prase(reply);




return 0;
}

5.程式碼 2

修改main函式

int main()
{

redisContext *c = redisConnect("127.0.0.1", 6379);

if (c == NULL || c->err) {
    if (c) {
        printf("Error:%s\n", c->errstr);
    } else {
        printf("conn't allocate redis context\n");
    }
    exit(-1);
}
printf("redis connect success\n");


redisReply *reply = (redisReply*)redisCommand(c, "set company noahwm");
prase(reply);
reply = (redisReply*)redisCommand(c, "set phone 17621079235");
prase(reply);


redisAppendCommand(c, "set family henan");
redisGetReply(c, (void**)&reply); // reply for SET                     
prase(reply);
reply = (redisReply*)redisCommand(c, "keys *");
prase(reply);

return 0;

}

如果使用完append類的command函式之後我們不使用redisGetReply得到回覆,那麼下一個命令的回覆就是上一條命令的回覆

相關推薦

hiredis(一個輕量級redis的c客戶)

1.簡單介紹hiredis是一個輕量級的訪問redis資料庫的c客戶端。它是輕量級的不僅僅是因為它僅僅提供對協議的最小支援,而且它使用了一個高級別的極度類似於printf的api使它的級別遠高於其最小程式碼庫和缺乏繫結的redis命令。簡而言之,就是更靈活。除了支援傳送命令和

一個基於JRTPLIB的輕量級RTSP客戶(myRTSPClient)——實現篇:(六)RTP音視頻傳輸解析層之音視頻數據傳輸格式

客戶端 會有 服務 client 基本 cnblogs 存在 額外 導致 一、差異 本地音視頻數據格式和用來傳輸的音視頻數據格式存在些許差異,由於音視頻數據流到達客戶端時,需要考慮數據流的數據邊界、分包、組包順序等問題,所以傳輸中的音視頻數據往往會多一些字節。 舉個例子

一個基於JRTPLIB的輕量級RTSP客戶(myRTSPClient)——實現篇:(九)以g711-mulaw為例添加新的編碼格式解析支持

調用 pcm 2個 h265 pri 源碼 返回 .cn memcpy 一、myRtspClient音頻解析架構 AudioTypeBase是處理解析各種編碼的音頻數據的接口類。處理MPA數據的MPEG_Audio類和處理g711-mulaw的PCMU_Audio類均從Au

推薦一個適用於SpringBoot專案的輕量級HTTP客戶框架,快來試試它!

在`SpringBoot`專案直接使用`okhttp`、`httpClient`或者`RestTemplate`發起`HTTP`請求,既繁瑣又不方便統一管理。因此,在這裡推薦一個適用於`SpringBoot`專案的輕量級HTTP客戶端框架[retrofit-spring-boot-starter](https

python---》客戶與服務的基礎(做一個簡單的客戶與服務

python 今天我們分享的內容是python簡單的客戶端與服務端,此處僅介紹一些簡單的函數,並作出來一個玩兒玩兒。 在開始之前呢,先用一張圖表示他們之間的關系 我們來按照這個步伐依次介紹:服務端:import socketserver=socket.socket()#此處是為了創建

用libevent開發一個http服務,附帶一個curl http客戶

對http互動較為陌生,所以最近寫了兩個小demo,一個http server 和一個http client,對於http server,很多人推薦使用libevent。http server:#include <stdlib.h> #include <st

Netty實戰(1)使用Netty搭建一個簡單的客戶與伺服器的互動Demo

       Netty 是一個基於 JAVA NIO 類庫的非同步通訊框架,它的架構特點是:非同步非阻塞、基於事件驅動、高效能、高可靠性和高可定製性。換句話說,Netty是一個NIO框架,使用它可以簡單快速地開發網路應用程式,比如客戶端和服務端的協議。Netty大大簡化了網

WebService_03使用CXF方式搭建一個簡單的客戶測試服務

1 需要一個官方提供的CXF工具 2 配置環境變數 3 執行dos命令 wsdl2java -p 包路經 -client 服務端的地址 必須精確到wsdl wsdl2java -p com.mr.service -client http://127.0.0.1/

Autossh-go寫的一個ssh遠端客戶

Autossh 用golang寫的一個ssh遠端客戶端。可一鍵登入遠端伺服器,主要用來彌補Mac Terminal ssh無法儲存密碼的不足。 使用Mac開發已有幾個月,一直沒有找到比較好用的ssh客戶端。SecureCRT有Mac版,始終覺得沒有自帶的

一個 Dribbble 第三方客戶

Dribbble 是一個優秀的設計師網站,這裡有上萬優秀設計師為移動開發人員提供了海量精美的 UI 資源。Dribbble 很早就開放了 API,也有許多優秀的第三方客戶端,本著學習的目的,我在課餘時間寫了這個還很粗糙的客戶端。目前的功能還很簡陋,使用者體驗也不是很完善,主要是因為 Dribbble 的 AP

socket多執行緒、一個伺服器多客戶的實現

鑑於ServerSocket的accept方法是阻塞的,那麼只能通過多執行緒的方式實現多客戶端連線與伺服器連線 基本步驟: 1,服務端建立ServerSocket繫結埠號,迴圈呼叫accept()方法 2,客戶端建立一個socket並請求和伺服器端連線 3,伺服器端接

在VS2015下配置websocket++,並用C++搭建一個簡單的客戶

簡介 最近在做一個專案,需要在C++中通過WebSocket和伺服器進行通訊,但我們在C++中並不能直接使用WebSocket,於是上網搜尋後發現websocket++這個庫很合適。 Websocket是基於HTTP協議的,或者說借用了HTTP的協議來完成一

實現一個輕量級高可復用的RabbitMQ客戶

情況下 如果 object stop str tel rri bind src 前言 ????本示例通過對服務訂閱的封裝、隱藏細節實現、統一配置、自動重連、異常處理等各個方面來打造一個簡單易用的 RabbitMQ 工廠;本文適合適合有一定 RabbitMQ 使用經驗的讀者閱

Linux c實現一個tcp文件服務器和客戶

repr snippets 功能 stderr strcpy fprintf inet_addr 編寫 create 總體需求:編寫tcp文件服務器和客戶端。客戶端可以上傳和下載文件。 ===========================================

[Unity3D 版本5.X]實現一個跟隨攝像機,聚焦到客戶主角身上

bsp mono pan 歐拉角 cnblogs button 右鍵 span htk 遊戲中的攝像機,都是聚焦到客戶端主角身上。 為了實現這個功能,我寫了兩個腳本,第一個腳本用來控制客戶端主角的位置和旋轉,使用WSAD鍵控制主角的前後左右移動,使用鼠標右鍵控制主角的旋轉。

公眾號和app和web都是客戶,都可以對接一個後臺

網站 clas span 端口 xxx 訪問 包括 包含 ext 1.公眾號和app和web都是客戶端,都可以對接一個後臺 2.域名中包含端口號嗎?:不包括,不包括 3.目前在IIS服務器上搭建了一個網站,域名也申請了,可是80端口不能使用,可以使用8000,每次訪問網

Explorer : 發布一個key-value存儲系統,帶有客戶和服務器

srv 方式 clas explorer 啟動服務 exp 默認 b+ .cn Explorer 一個key-value存儲系統,帶有客戶端和服務器端。使用非常方便。 使用B+樹作為存儲引擎,客戶端和服務器端使用TCP協議進行通信。 代碼采用C++實現,底層將客

編寫一個簡單的TCP服務客戶

不同的 大連 終端 服務器端 com 讀寫 所有 字數 資料 下面的實驗環境是linux系統。 效果如下: 1.啟動服務端程序,監聽在6666端口上 2.啟動客戶端,與服務端建立TCP連接 3.建立完TCP連接,在客戶端上向服務端發送消息 4.斷開

C#使用Socket實現一個socket服務器與多個socket客戶通信

當前 rec inf hide 負責 new 數據庫 class 多臺   在分布式調度系統中,如果要實現調度服務器與多臺計算節點服務器之間通信,采用socket來實現是一種實現方式,當然我們也可以通過數據存儲任務,子節點來完成任務,但是往往使用數據作為任務存儲都需要定制開