CentOS 编译安装Redis

一、编译配置hiredis.h

C++来操作redis数据库。通过hiredis接口来实现,目前只能在Linux环境使用。

  • 下载hiredis.h

  • hiredis的下载地址为: https://github.com/redis/hiredis

  • 解压并编译hiredis

    [root@localhost source_code]# pwd
    /usr/local/source_code
    [root@localhost source_code]# ll
    总用量 5296
    drwxr-xr-x. 2 root root 42 9月 18 17:32 c_demo
    -rw-r--r--. 1 root root 126216 10月 10 09:42 hiredis-1.2.0.tar.gz
    drwxr-xr-x. 5 500 users 8192 9月 4 15:28 jpeg-9e
    -rw-r--r--. 1 root root 1046935 9月 4 15:23 jpegsrc.v9e.tar.gz
    -rw-r--r--. 1 root root 4234219 8月 31 16:22 release-3.4.13.tar.gz
    drwxrwxr-x. 8 root root 259 8月 31 16:33 zookeeper-release-3.4.13
    [root@localhost source_code]# tar -zxvf hiredis-1.2.0.tar.gz
    hiredis-1.2.0/
    hiredis-1.2.0/.github/
    hiredis-1.2.0/.github/release-drafter-config.yml


  • 执行make && make install(自动把libhiredis.so放到/usr/local/lib/中,把hiredis.h放到/usr/local/inlcude/hiredis/中)

    [root@localhost source_code]# cd hiredis-1.2.0
    [root@localhost hiredis-1.2.0]# make && make install
    cc -std=c99 -c -O3 -fPIC -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -g -ggdb -pedantic alloc.c
    cc -std=c99 -c -O3 -fPIC -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -g -ggdb -pedantic net.c
    cc -std=c99 -c -O3 -fPIC -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -g -ggdb -pedantic hiredis.c


    生成hredis 相关信息

    mkdir -p /usr/local/include/hiredis /usr/local/include/hiredis/adapters /usr/local/lib
    -- hiredis 头文件生成地址
    cp -pPR hiredis.h async.h read.h sds.h alloc.h sockcompat.h /usr/local/include/hiredis
    cp -pPR adapters/*.h /usr/local/include/hiredis/adapters
    -- hiredis 动态库文件生成地址
    cp -pPR libhiredis.so /usr/local/lib/libhiredis.so.1.1.0
    cd /usr/local/lib && ln -sf libhiredis.so.1.1.0 libhiredis.so && ln -sf libhiredis.so.1.1.0 libhiredis.so.1
    cp -pPR libhiredis.a /usr/local/lib
    mkdir -p /usr/local/lib/pkgconfig
    cp -pPR hiredis.pc /usr/local/lib/pkgconfig

在程序中包含#include <hiredis/hiredis.h>即可

[root@localhost ~]# cd /usr/local/source_code/
[root@localhost source_code]# ll
总用量 5300
drwxr-xr-x. 2 root root       42 9月  18 17:32 c_demo
drwxrwxr-x. 6 root root     4096 10月 10 09:44 hiredis-1.2.0
-rw-r--r--. 1 root root   126216 10月 10 09:42 hiredis-1.2.0.tar.gz
drwxr-xr-x. 2 root root       50 10月 10 10:37 hiredis_demo
drwxr-xr-x. 5  500 users    8192 9月   4 15:28 jpeg-9e
-rw-r--r--. 1 root root  1046935 9月   4 15:23 jpegsrc.v9e.tar.gz
-rw-r--r--. 1 root root  4234219 8月  31 16:22 release-3.4.13.tar.gz
drwxr-xr-x. 2 root root        6 10月 10 10:58 zookeeper_demo
drwxrwxr-x. 8 root root      259 8月  31 16:33 zookeeper-release-3.4.13
[root@localhost source_code]# cd hiredis_demo/
[root@localhost hiredis_demo]# ll
总用量 16
-rwxr-xr-x. 1 root root 8608 10月 10 10:37 hiredis_demo
-rw-r--r--. 1 root root  697 10月 10 10:26 hiredis_demo.cpp
[root@localhost hiredis_demo]# cat hiredis_demo.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>

int main() {
    redisContext *c;
    redisReply *reply;

    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    c = redisConnectWithTimeout((char*)"192.168.43.80", 6379, timeout);

    if (c != NULL && c->err)
    {
        printf("Connection error: %s", c->errstr);
        redisFree(c);
        exit(1);
    }

    reply = (redisReply *)redisCommand(c, "SET %s %s", "foo", "bar");
    freeReplyObject(reply);

    reply = (redisReply *)redisCommand(c, "GET foo");

    printf("foo: %s", reply->str);
    freeReplyObject(reply);

    redisFree(c);

    return 0;
}
[root@localhost hiredis_demo]#
  • 编译代码的时候需要加链接的库及库的路径,那么编译命令如下

    g++ hiredis_demo.cpp -o hiredis_demo -L/usr/local/lib/ -lhiredis

  • 在执行的时候如果出现动态库无法加载。

    [root@localhost hiredis_demo]# ./hiredis_demo
    ./hiredis_demo: error while loading shared libraries: libhiredis.so.1.1.0: cannot open shared object file: No such file or directory
    

    那么需要进行如下配置。

  • 在 /etc/ld.so.conf.d/ 目录下新建文件 usr-libs.conf ,内容是: /usr/local/lib

    vim /etc/ld.so.conf.d/usr-libs.conf

  • 然后使用命令 /sbin/ldconfig 更新一下配置即可。

    sbin/ldconfig

二、hiredis.h核心方法

第一步:查看hiredis.h 头文件定义:

[root@localhost lib]# cd /usr/local/include/hiredis/
[root@localhost hiredis]# ll
总用量 56
drwxr-xr-x. 2 root root   197 10月 10 09:44 adapters
-rw-rw-r--. 1 root root  3130 7月  12 15:31 alloc.h
-rw-rw-r--. 1 root root  6288 7月  12 15:31 async.h
-rw-rw-r--. 1 root root 14319 7月  12 15:31 hiredis.h
-rw-rw-r--. 1 root root  4918 7月  12 15:31 read.h
-rw-rw-r--. 1 root root  9238 7月  12 15:31 sds.h
-rw-rw-r--. 1 root root  4409 7月  12 15:31 sockcompat.h
[root@localhost hiredis]# cat hiredis.h

核心方法定义

1.建立链接:redisConnect

redisContext* redisConnect(const char *ip, int port)

函数说明:

  • 函数用来连接redis数据库, 两个参数分别是redis数据库的ip和端口,端口号一般为6379
  • 该函数redisConnect用于创建所谓的redisContext。上下文是Hiredis保持连接状态的地方。
  • 当连接处于错误状态时,该redisContext 结构具有一个err非零的整数字段该字段errstr将包含带有错误描述的字符串
  • 使用尝试连接到Redis后redisConnect,应检查该err字段以查看建立连接是否成功

还提供了一个函数,供连接超时限定,即

redisContext* redisConnectWithTimeout(const char *ip, 
											int port, timeval tv)。

Demo 示例:

 c = redisConnectWithTimeout((char*)"192.168.43.80", 6379, timeout);

    if (c != NULL && c->err)
    {
        printf("Connection error: %s", c->errstr);
        redisFree(c);
        exit(1);
    }

解释说明:

当函数调用不成功时,取决于函数NULL还是REDIS_ERR返回。err上下文中的字段将为非零值,并设置为以下常量之一:

  • REDIS_ERR_IO:创建连接,尝试写入套接字或从套接字读取时发生I /O错误。如果您包含errno.h在应用程序中,则可以使用全局errno变量来找出问题所在。
  • REDIS_ERR_EOF:服务器关闭了连接,导致读取为空。
  • REDIS_ERR_PROTOCOL:解析协议时出错。
  • REDIS_ERR_OTHER:其他任何错误。当前,仅在无法解析要连接的指定主机名时使用。

在每种情况下,errstr上下文中的字段都将设置为包含错误的字符串表示形式。

2. 执行redis命令:redisCommand

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

函数说明:

  • 该函数用于执行redis数据库中的命令,第一个参数为连接数据库返回的redisContext,剩下的参数为变参。

  • 此函数的返回值为void*,但是一般会强制转换为redisReply类型,以便做进一步的处理。

const char *format... 动态参数关联方法定义:

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

函数说明:

  • 它需要参数的数量,argc字符串数组argv和参数的长度argvlen。
  • 为了方便起见,argvlen可以将设置为NULL,并且函数将strlen(3)在每个参数上使用以确定其长度。
  • 显然,当任何一个参数需要二进制安全时,argvlen都应提供整个长度数组。
  • 返回值的语义与相同redisCommand。

Demo 示例:

 reply = (redisReply *)redisCommand(c, "SET %s %s", "foo", "bar");

3.释放redisCommand

void freeReplyObject(void *reply)

函数说明:

  • 释放redisCommand执行后返回的的redisReply所占用的内存。
  • redisCommand成功执行命令后,的返回值将保留答复。
  • 发生错误时,返回值为NULL并且err将设置上下文中的字段。返回错误后,上下文context将无法重用,您应该建立一个新的连接。

Demo 示例:

 freeReplyObject(reply);

4.断开连接:redisFree

void redisFree(redisContext *c)

函数说明:

  • 此函数立即关闭套接字,然后释放在创建上下文时完成的分配。

三、Hiredis 基于C++ 封装

redis_handler.h

#ifndef __REDIS_HANDLER_H__
#define __REDIS_HANDLER_H__
 
#include <hiredis/hiredis.h>
#include <string>

using namespace std;

enum
{
    M_REDIS_OK = 0, //执行成功
    M_CONNECT_FAIL = -1, //连接redis失败
    M_CONTEXT_ERROR = -2, //RedisContext返回错误
    M_REPLY_ERROR = -3, //redisReply错误
    M_EXE_COMMAND_ERROR = -4 //redis命令执行错误
};


class RedisHandler
{
public:
    RedisHandler();
    ~RedisHandler();
    int connect(const string &addr, int port, const string &pwd = ""); //连接redis数据库:addr:IP地址,port:端口号,pwd:密码(默认为空)
    int disConnect(); //断开连接

    int setValue(const string &key, const string &value); //添加或修改键值对,成功返回0,失败<0
    int getValue(const string &key, string &value); //获取键对应的值,成功返回0,失败<0
    int delKey(const string &key); //删除键,成功返回影响的行数,失败<0
    int printAll(); //打印所有的键值对

    string getErrorMsg(); //获取错误信息
private:
    string m_addr; //IP地址
    int m_port; //端口号
    string m_pwd; //密码
    redisContext* pm_rct; //redis结构体
    redisReply* pm_rr; //返回结构体
    string error_msg; //错误信息

    int connectAuth(const string &pwd); //使用密码登录
    int handleReply(void* value = NULL, redisReply ***array = NULL); //处理返回的结果
};


#endif

redis_handler.cpp

#include "redis_handler.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std;

RedisHandler::RedisHandler()
{
    m_addr = "";
    m_port = 0;
    m_pwd = "";
    pm_rct = NULL;
    pm_rr = NULL;
    error_msg = "";
}

RedisHandler::~RedisHandler()
{
    disConnect();
    pm_rct = NULL;
    pm_rr = NULL;
}

/*
连接redis数据库
addr: 地址,port:端口号,pwd:密码
成功返回M_REDIS_OK,失败返回M_CONNECT_FAIL
*/
int RedisHandler::connect(const string &addr = "127.0.0.1", int port = 6379, const string &pwd) {
    m_addr = addr;
    m_port = port;
    m_pwd = pwd;

    pm_rct = redisConnect(m_addr.c_str(), m_port);

    if (pm_rct->err)
    {
        error_msg = pm_rct->errstr;
        return M_CONNECT_FAIL;
    }

    if (!m_pwd.empty())
    {
        return connectAuth(m_pwd);
    }

    return M_REDIS_OK;
}

/*
断开redis连接
*/
int RedisHandler::disConnect()
{
    redisFree(pm_rct);
    freeReplyObject(pm_rr);
}

/*
添加或插入键值对
key:键,value:值
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::setValue(const string &key, const string &value)
{
    string cmd = "set " + key + " " + value;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    return handleReply();
}

/*
获取键对应的值
key:键,value:值引用
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::getValue(const string &key, string &value)
{
    string cmd = "get " + key;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    int ret = handleReply(&value);
}

/*
删除键
key:键
成功返回影响的行数(可能为0),失败返回<0
*/
int RedisHandler::delKey(const string &key)
{
    string cmd = "del " + key;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    int rows = 0;
    int ret = handleReply(&rows);
    if (ret == M_REDIS_OK)
        return rows;
    else
        return ret;
}

/*
打印所有键值对到屏幕上
*/
int RedisHandler::printAll()
{
    string cmd = "keys *";

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    int len ;
    redisReply **array;
    int ret = handleReply(&len, &array);
    if (ret == M_REDIS_OK)
    {
        for (int i = 0; i < len; i++)
            cout << string(array[i]->str) << endl;
    }
    else
        return 0;
}

/*
返回错误信息
*/
string RedisHandler::getErrorMsg()
{
    return error_msg;
}

/*
使用密码登录
psw:登录密码
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::connectAuth(const string &psw)
{
    string cmd = "auth " + psw;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    return handleReply();
}

/*
处理redis返回的信息
value:数据指针,用于保存redis返回的基本类型(value指针指向该数据)
array:数组指针,用于保存redis返回的数组
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::handleReply(void* value, redisReply*** array)
{
    if (pm_rct->err)
    {
        error_msg = pm_rct->errstr;
        return M_CONTEXT_ERROR;
    }

    if (pm_rr == NULL)
    {
        error_msg = "auth redisReply is NULL";
        return M_REPLY_ERROR;
    }

    switch (pm_rr->type)
    {
    case REDIS_REPLY_ERROR:
        error_msg = pm_rr->str;
        return M_EXE_COMMAND_ERROR;
    case REDIS_REPLY_STATUS:
        if (!strcmp(pm_rr->str, "OK"))
            return M_REDIS_OK;
        else
        {
            error_msg = pm_rr->str;
            return M_EXE_COMMAND_ERROR;
        }
    case REDIS_REPLY_INTEGER:
        *(int*)value = pm_rr->integer;
        return M_REDIS_OK;
    case REDIS_REPLY_STRING:
        *(string*)value = pm_rr->str;
        return M_REDIS_OK;
    case REDIS_REPLY_NIL:
        *(string*)value = "";
        return M_REDIS_OK;
    case REDIS_REPLY_ARRAY:
        *(int*)value = pm_rr->elements;
        *array = pm_rr->element;
        return M_REDIS_OK;
    default:
        error_msg = "unknow reply type";
        return M_EXE_COMMAND_ERROR;
    }
}

Demo 示例:

redis_main.cpp

#include <iostream>
#include <string>
#include "redis_handler.h"
using namespace std;

int main()
{
    RedisHandler* rh = new RedisHandler();
    int ret;

    //连接测试
    cout << "错误测试: " << "地址错误" << endl;
    ret = rh->connect("34.15.14.15", 6379, "linesum");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;

    cout << "错误测试: " << "端口错误" << endl;
    ret = rh->connect("127.0.0.1", 1234, "linesum");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;

    cout << "错误测试: " << "密码错误" << endl;
    ret = rh->connect("127.0.0.1", 6479, "linsum");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;


    ret = rh->connect("127.0.0.1", 6479, "linesum");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }


    //set测试
    cout << "错误测试: " << "set不带value参数" << endl;
    ret = rh->setValue("key11", "");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;


    ret = rh->setValue("key11", "value11");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }

    ret = rh->setValue("key22", "value22");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }


    //get测试
    string str;
    cout << "错误测试: " << "get不带key参数" << endl;
    ret = rh->getValue("key1111", str);
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;

    ret = rh->getValue("key11", str);
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }
    else
        cout << "value : " << str << endl;



    //print测试
    ret = rh->printAll();
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }


    //del测试
    cout << "错误测试: " << "删除不存在的key" << endl;
    ret = rh->delKey("key1111");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;


    ret = rh->delKey("key11");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }

    delete rh;

    return 0;
}
相关推荐
勘察加熊人5 分钟前
fastapi房产销售系统
数据库·lua·fastapi
m0_7482546622 分钟前
MySQL和SQL server的区别
数据库·mysql
补三补四24 分钟前
Yashan DB 实例
数据库·oracle·dba
食指Shaye28 分钟前
Chrome 中清理缓存的方法
前端·chrome·缓存
morris1311 小时前
【redis】布隆过滤器的Java实现
java·redis·布隆过滤器
椰椰椰耶1 小时前
【redis】全局命令set、get、keys
数据库·redis·缓存
月落星还在1 小时前
Redis 内存淘汰策略深度解析
数据库·redis·缓存
五行星辰1 小时前
Java链接redis
java·开发语言·redis
左灯右行的爱情1 小时前
Redis- 切片集群
数据库·redis·缓存
LKAI.1 小时前
MongoDB用户管理和复制组
linux·数据库·mongodb