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來實現是一種實現方式,當然我們也可以通過數據存儲任務,子節點來完成任務,但是往往使用數據作為任務存儲都需要定制開