Redis 客戶端 Hiredis 簡介
學習總結一下官方釋出的C版本客戶端 hiredis
,瞭解hiredis
客戶端大致實現細節。在理解程式碼之間需要了解通訊協議的特點,我上一篇轉載的文章已經有過介紹,大家可以去看一下。
hiredis
提供了同步、非同步訪問,非同步 API 需要與一些事件庫協同工作,主要看一下同步API的實現。
hiredis
與服務端通訊的API比較簡單,主要有這幾個步驟:
- 建立連線
- 傳送命令
- 等待結果並處理
- 釋放連線
一、相關資料結構
redisContext
儲存連線建立後的上下文。 err
儲存錯誤碼,如果為0表示沒錯,如果非0那麼錯誤說明儲存在 errstr
中;fd
是連線建立後的套接字;flags
obuf
儲存要向 redis-server
傳送的命令內容;reader
用來讀取從服務端返回的訊息,redisReader
中的buf
成員用來儲存內容;connection_type
表示連線型別,有兩種分別是REDIS_CONN_TCP
和 REDIS_CONN_UNIX
;timeout
是連線時指定的超時時間。
/* Context for a connection to Redis */
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;
/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
int type; /* REDIS_REPLY_* */
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
size_t len; /* Length of string */
char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
redisReply
這個結構是儲存傳送命令後得到的返回結果,type
表示伺服器返回結果的型別,比如 REDIS_REPLY_STRING
,表示返回一個 string
,此時內容就儲存在 str
這個成員中,其他成員類似。有下面這幾種型別:
#define REDIS_REPLY_STRING 1
#define REDIS_REPLY_ARRAY 2
#define REDIS_REPLY_INTEGER 3
#define REDIS_REPLY_NIL 4
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6
(二)相關 api
建立連線
redisContext *redisConnect(const char *ip, int port);
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
redisContext *redisConnectNonBlock(const char *ip, int port);
redisContext *redisConnectBindNonBlock(const char *ip, int port,
const char *source_addr);
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
const char *source_addr);
redisContext *redisConnectUnix(const char *path);
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
redisContext *redisConnectFd(int fd);
這些 api 都是建立連線的,可以根據需求或者條件選擇合適的。連線建立成功返回 redisContext
,將連線資訊放到這個結構中,通過 err
成員來判斷是否建立成功。
傳送命令並等待結果
redisCommand
和 redisAppendCommand
系列函式用來向伺服器傳送命令。
redisCommand
-> redisvCommand
-> redisvAppendCommand
-> __redisAppendCommand
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
sds newbuf;
newbuf = sdscatlen(c->obuf,cmd,len);
if (newbuf == NULL) {
__redisSetError(c,REDIS_ERR_OOM,"Out of memory");
return REDIS_ERR;
}
c->obuf = newbuf;
return REDIS_OK;
}
這個函式組裝傳送的命令到redisContext
的 obuf
中,obuf
可以動態擴容,所以不用擔心溢位;接下來在函式 redisCommand
中呼叫 __redisBlockForReply
,繼而呼叫 redisGetReply
這個函式來獲取返回結果。
int redisGetReply(redisContext *c, void **reply) {
int wdone = 0;
void *aux = NULL;
/* Try to read pending replies */
if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
return REDIS_ERR;
/* For the blocking context, flush output buffer and read reply */
if (aux == NULL && c->flags & REDIS_BLOCK) {
/* Write until done */
do {
if (redisBufferWrite(c,&wdone) == REDIS_ERR)
return REDIS_ERR;
} while (!wdone);
/* Read until there is a reply */
do {
if (redisBufferRead(c) == REDIS_ERR)
return REDIS_ERR;
if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
return REDIS_ERR;
} while (aux == NULL);
}
/* Set reply object */
if (reply != NULL) *reply = aux;
return REDIS_OK;
}
這個函式分下面幾步實現:
- 首先檢視 redisReader
結構中的 buf
成員是否有資料,有的話則解析出 reply
並返回,否則進入下面;
- 把 obuf
緩衝區的資料全部寫入 c->fd
,寫完後釋放 obuf
;
- 接下來阻塞讀取伺服器返回的結果並將其放入redisContext
-> redisReader
-> buf
緩衝區中,進入下一步;
- 呼叫 redisGetReplyFromReader
解析 buf
中的資料,並返回reply
;獲取到的 redisReply
物件需要呼叫 freeReplyObject
顯式釋放,否則會洩漏。
redisAppendCommand
這個函式將傳送的命令格式化放入 redisContext
的 obuf
中,可以一次傳送多條命令,然後接收一批結果,結果按照發送命令的順序儲存,這裡利用了 pipeline
特性,可以減少網路傳輸的次數,提高IO吞吐量。
釋放連線
使用完一個連線後需要呼叫 redisFree
函式來釋放這個連線,主要是關閉套接字,釋放申請的緩衝區。
void redisFree(redisContext *c) {
if (c == NULL)
return;
if (c->fd > 0)
close(c->fd);
sdsfree(c->obuf);
redisReaderFree(c->reader);
free(c->tcp.host);
free(c->tcp.source_addr);
free(c->unix_sock.path);
free(c->timeout);
free(c);
}
一個例子
下面給出一個例子,對這幾個API最基本的使用,測試的時候需要先安裝 redis-server
並啟動,預設埠為 6379
,同時需要安裝 hiredis
庫,sudo yum install hiredis-devel
,或者原始碼安裝。
/*************************************************************************
> File Name: redis-cli.c
> Author: Tanswer_
> Mail: [email protected]
> Created Time: Thu Jun 28 15:49:43 2018
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>
int main()
{
redisContext* c = redisConnect((char*)"127.0.0.1", 6379);
if(c->err){
redisFree(c);
return 0;
}
printf("connect redis-server success.\n");
const char* command = "set good luck";
redisReply* r = (redisReply*)redisCommand(c, command);
if(r == NULL){
redisFree(c);
return 0;
}
if(!(r->type == REDIS_REPLY_STATUS && strcasecmp(r->str, "OK") == 0)){
printf("Failed to execute command[%s].\n", command);
freeReplyObject(r);
redisFree(c);
return 0;
}
freeReplyObject(r);
printf("Succeed to execute command[%s].\n", command);
const char* command1 = "strlen good";
r = (redisReply*)redisCommand(c, command1);
if(r->type != REDIS_REPLY_INTEGER){
printf("Failed to execute command[%s].\n", command1);
freeReplyObject(r);
redisFree(c);
return 0;
}
int length = r -> integer;
freeReplyObject(r);
printf("The length of 'good' is %d.\n", length);
printf("Succeed to execute command[%s].\n", command1);
const char* command2 = "get good";
r = (redisReply*)redisCommand(c, command2);
if(r -> type != REDIS_REPLY_STRING){
printf("Failed to execute command[%s].\n", command2);
freeReplyObject(r);
redisFree(c);
return 0;
}
printf("The value of 'goo' is %s.\n", r->str);
freeReplyObject(r);
printf("Succeed to execute command[%s].\n", command2);
redisFree(c);
return 0;
}
相關推薦
Redis 客戶端 Hiredis 簡介
學習總結一下官方釋出的C版本客戶端 hiredis,瞭解hiredis 客戶端大致實現細節。在理解程式碼之間需要了解通訊協議的特點,我上一篇轉載的文章已經有過介紹,大家可以去看一下。 hiredis 提供了同步、非同步訪問,非同步 API 需要與一些事件庫協同
Redis C客戶端Hiredis代碼分析
-s sta 代碼分析 sge immediate sap pat process serve 初始化 redisContext - Redis連接的上下文 /* Context for a connection to Redis */ typedef struct re
redis記憶體資料庫C客戶端hiredis API 中文說明
A)編譯安裝 make make install (/usr/local) make install PREFIX=$HOME/progs(可以自由指定安裝路徑) B)同步的API介面 redisContext *redisConnect(const char *ip, int port
redis的C客戶端---hiRedis使用
redis的C客戶端—hiRedis使用 1. 客戶端通訊協議 Redis 制定了 **RESP(REdis Serialization Protocol,Redis 序列 化協議)**實現客戶端與服務端的正常互動,這種協議簡單高效,既能夠被機器解析,又容易被
Linux安裝編譯安裝hiredis,使得Swoole支援非同步Redis客戶端
編譯安裝hiredis 使用Redis客戶端,需要安裝hiredis庫。下載hiredis原始碼後,執行 make -j sudo make install sudo ldconfig hiredis下載地址:https://github.com/redis/hiredis/re
Redis-C客戶端-HiRedis-(二)
前幾篇介紹了redis以及phpredis,主要是因為我所在的專案組用的是php,而我接下來的一個小任務是用c++寫一個處理儲存在redis裡的業務資料的小工具,在redis官方上看推薦的c++客戶端,只有一個,而且還是2年前的一個臨時專案,而且還要依賴boost,而且看開發者的口氣,實在是覺得不敢用啊~
Redis客戶端連線方式Hiredis簡單封裝使用,連線池、遮蔽連線細節
轉:https://blog.csdn.net/gdutliuyun827/article/details/44339007對Hiredis進行了簡單封裝,實現功能:1、API進行統一,對外只提供一個介面;2、遮蔽上層應用對連線的細節處理;3、底層採用佇列的方式保持連線池,儲
常用的Redis客戶端的並發模型(轉)
war sta 進程 過程 blog 有效 tro nal 做的 偽代碼模型 # get lock lock = 0 while lock != 1: timestamp = current Unix time + lock timeou
redis 客戶端無密碼交互刪除key
redisredis-cli -h www.badiu.com -a **** keys ‘key‘| xargs redis-cli -h www.abidu.com -a **** del-a 密碼www.baidu.com 地址本文出自 “磚家博客” 博客,請務必保留此出處http://wsxx
Redis 通信協議-了解 Redis 客戶端實現原理
dubbo redis java 簡介幾乎所有的主流編程語言都有Redis的客戶端(http://redis.io/clients),不考慮Redis非常流行的原因,如果站在技術的角度看原因還有兩個:客戶端與服務端之間的通信協議是在 TCP 協議之上構建的。客戶端和服務器通過 TCP 連接來進行數
全球領先的redis客戶端:SFedis
自帶 修改 標準 做了 red 崗位 and 穿透 監控 零、背景 這個客戶端起源於我們一個系統的生產問題。 一、問題的發生 在我們的生產環境上發生了兩次redis服務端連接數達到上限(我們配置的單節點連接數上限為8000)導致無法創建連接的情況。由於這
Redis學習筆記--Redis客戶端(三)
本機 -c trace 圖形 tro cli family 毫秒 ati 1.Redis客戶端 1.1 Redis自帶的客戶端 (1)啟動 啟動客戶端命令:[root@kwredis bin]# ./redis-cli -h 127.0.0.1 -p 6379
Redis 客戶端連接
-i ace back gpo word color clas tab cli Redis 客戶端連接 Redis 通過監聽一個 TCP 端口或者 Unix socket 的方式來接收來自客戶端的連接,當一個連接建立後,Redis 內部會進行以下一些操作: 首先,客戶端
[ 搭建Redis本地服務器實踐系列三 ] :圖解Redis客戶端工具連接Redis服務器
done not 必須 tin 復雜 start exe eas 方便 上一章 [ 搭建Redis本地服務器實踐系列二 ] :圖解CentOS7配置Redis 介紹了Redis的初始化腳本文件及啟動配置文件,並圖解如何以服務的形式來啟動、終止Redis服務,可以說我們的R
阿裏雲專訪Redisson作者Rui Gu:構建開源企業級Redis客戶端之路
為什麽 前景 clas 數據 value 計算機行業 編程 alt 階段 摘要: 本文為阿裏雲同學在RedisConf2018上對Redisson開源客戶端作者Rui Gu做的一個專訪,主要介紹了Rui Gu參與開啟Redisson客戶端開發的歷程,同時也詳細介紹了Redi
redis客戶端連接,最大連接數查詢與設置
指定 col node 網絡 service服務 限制 style nbsp free ##redis客戶端連接數 redis通過監聽一個TCP端口或socket的方式接收來自客戶端的連接, 當與客戶端建立連接後,redis內部會進行如下操作:(1)客戶端socket會
配置Redis客戶端
pro code bsp client edi class cli nts 客戶端 <properties> <jedis.version>2.7.2</jedis.version> </properties> &
windows 系統 使用 redis 客戶端
有時會就是想測試一下redis 有沒有用 但是又不想跑專案, 這個時候就很有必要使用 window 的方式來連結redis 其實很簡單 1.再redis 目錄下開啟命令視窗 比較快捷的方式就是在位址列輸入cmd 再回車 2.再命令欄執行 redis-cli.ex
Jedis連線redis客戶端
1 單點的redis利用jedis客戶端連線 如何連線 1 //1 利用jedis連線物件操作redis 2 @Test 3 public void test01(){ 4 //構造一個具有連線資訊的jedis物件 5 //確定虛擬機器linux系
Redis---客戶端和服務端
Redis---客戶端和服務端 文章轉載自:http://redisbook.readthedocs.io/en/latest/internal/redis.html http://www.spongeliu.com/category/linux https://blo