github下载最新的:git clone https://github.com/redis/hiredis.git
也可下载历史稳定版本(当前v1.0.2):https://github.com/redis/hiredis/tags, wget https://github.com/redis/hiredis/archive/refs/tags/v1.0.2.tar.gz
#解压并进入hiredis目录
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=<install dir> ..
$ make
$ make install
封装部分功能:
#include
#include
#include
class RedisClient {
public:
RedisClient() : m_client(NULL) {}
~RedisClient() {
if (m_client) {
redisFree(m_client);
}
}
bool Init(const std::string& hostname, int port) {
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
m_client = redisConnectWithTimeout(hostname.c_str(), port, timeout);
if (m_client == NULL || m_client->err) {
if (m_client) {
printf("Connection error: %s\n", m_client->errstr);
redisFree(m_client);
} else {
printf("Connection error: can't allocate redis context\n");
}
return false;
}
printf("Connection success!\n");
return true;
}
bool Ping() {
if (!m_client) {
return false;
}
redisReply *reply;
reply = (redisReply*)redisCommand(m_client, "PING");
if (reply) {
// printf("reply->type: %d, reply->str: %s, reply->integer: %d\n", reply->type, reply->str, reply->integer);
if (reply->type == REDIS_REPLY_STATUS && strncmp(reply->str, "PONG", 4) == 0) {
freeReplyObject(reply);
return true;
}
freeReplyObject(reply);
}
return false;
}
bool Del(const std::string& key) {
redisReply *reply = (redisReply*)redisCommand(m_client, "DEL %s", key.c_str());
if (reply) {
// printf("reply->type: %d, reply->str: %s, reply->integer: %d\n", reply->type, reply->str, reply->integer);
if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) {
freeReplyObject(reply);
return true;
}
freeReplyObject(reply);
return false;
}
return false;
}
// 使用lua脚本确保删除的是之前设置的,避免误删
bool Del(const std::string& key, const std::string& value) {
redisReply *reply;
std::string luaScript = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end";
reply = (redisReply*)redisCommand(m_client, "EVAL %s 1 %s %s", luaScript.c_str(), key.c_str(), value.c_str());
//reply = (redisReply*)redisCommand(m_client, "DEL %s", key.c_str());
if (reply) {
// printf("reply->type: %d, reply->str: %s, reply->integer: %d\n", reply->type, reply->str, reply->integer);
if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) {
freeReplyObject(reply);
return true;
}
freeReplyObject(reply);
return false;
}
return false;
}
// count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
// count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
// count = 0 : 移除表中所有与 value 相等的值。
bool LRem(const std::string& key, const std::string& value, int count = 0) {
if (!m_client) {
return false;
}
redisReply *reply;
reply = (redisReply*)redisCommand(m_client, "LREM %s %d %s", key.c_str(), count, value.c_str());
if (reply) {
freeReplyObject(reply);
return true;
}
return false;
}
//设置key
// EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
// PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
// NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
// XX :只在键已经存在时,才对键进行设置操作。
// 目前只设置 PX、NX, 实现带锁的分布式
bool Set(const std::string& key, const std::string& value, int timeout) {
if (!m_client) {
return false;
}
redisReply *reply;
reply = (redisReply*)redisCommand(m_client, "SET %s %s PX %d NX", key.c_str(), value.c_str(), timeout);
if (reply) {
// printf("reply->type: %d, reply->str: %s, reply->integer: %d\n", reply->type, reply->str, reply->integer);
if (reply->type == REDIS_REPLY_NIL) {
freeReplyObject(reply);
return false;
}
if (reply->type == REDIS_REPLY_STATUS && strncmp(reply->str, "OK", 2) == 0) {
freeReplyObject(reply);
return true;
}
freeReplyObject(reply);
return false;
}
return false;
}
private:
redisContext *m_client;
};
测试代码:
#include
#include
#include
#include
#include
#include "RedisClient.h"
void TestDistributed(RedisClient* client) {
std::ostringstream ss;
ss << std::this_thread::get_id();
std::string value = ss.str();
while (true) {
if (client->Ping()) {
//timeout 3000
if (!client->Set("job", value, 3000)) {
printf("%s Set failed!\n", value.c_str());
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
} else {
//do something
printf("%s Acquire the lock!\n", value.c_str());
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
//finished, unlock
if (!client->Del("job", value)) {
printf("Del job1 error\n");
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
int main() {
for (int i = 0; i != 3; ++i) {
std::thread([&](){
RedisClient* client = new RedisClient();
if (!client->Init("192.168.11.245", 63790)) {
return 0;
}
TestDistributed(client);
}).detach();
}
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(100));
}
return 0;
}