当前位置: 首页 > news >正文

redis客户端库redis++在嵌入式Linux下的交叉编译及使用

在开发过程中,我们经常会遇到需要在嵌入式Linux系统上与Redis进行交互的需求。因此选择一个适合的Redis客户端库就显得尤为重要。下面介绍下c++中有名的redis-plus-plus(redis++)三方库在嵌入式linux下的交叉编译及使用。该库底层是基于hiredis的良好封装,具备良好的性能。

在C++环境下,hiredishirredisvip是最基础的选择,但它们并没有封装连接池、自动重连等功能,这使得它们在复杂场景中显得力不从心。特别是hiredis,它本身不是线程安全的,每个线程应该维护自己的连接对象,不可在多个线程之间共享一个连接对象。多个线程同时使用同一个连接对象会导致数据竞争和不确定的行为。

还有其他一些库如cloredis,它能够支持集群和单机模式,并且自带连接池功能,但它对Redis哨兵模式的支持并不理想。而redisplus plus这个库,不仅支持Redis的大多数功能,而且提供了更高级的封装和特性,比如自动重连、连接池、哨兵模式等,极大地方便了我们的开发工作。

Redis++介绍

redis++是Redis官网推荐的C++连接库之一,其开源地址为:https://github.com/sewenew/redis-plus-plus。这个库基于hiredis,但提供了更为强大的功能和更好的使用体验。它支持Redis的大多数特性,并对这些特性进行了C++风格的封装,使得在C++项目中使用Redis更加得心应手。

准备交叉编译工具链

在嵌入式Linux开发中,我们通常需要进行交叉编译。这里以ARM和RISC-V架构为例,提供一个配置文件toolchain.cmake,用于设置交叉编译工具链。

# 交叉编译工具链配置文件
# 用于嵌入式Linux系统和RISC-V MCU的交叉编译# 设置系统名称
set(CMAKE_SYSTEM_NAME Linux)# 设置处理器架构变量,可以通过命令行参数传入
# 例如: cmake -DTARGET_ARCH=arm ..
if(NOT DEFINED TARGET_ARCH)set(TARGET_ARCH "arm" CACHE STRING "Target architecture (arm or riscv)")
endif()# 设置ARM工具链路径
set(ARM_TOOLCHAIN_PATH "/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi")
# 设置RISC-V工具链路径
set(RISCV_TOOLCHAIN_PATH "/opt/tronlong/tina5.0_v1.0/rtos/lichee/rtos/tools/riscv64-elf-x86_64-20201104")# 根据目标架构设置主工具链
if(${TARGET_ARCH} STREQUAL "arm")# ARM Linux工具链配置set(CMAKE_C_COMPILER ${ARM_TOOLCHAIN_PATH}/arm-poky-linux-gnueabi-gcc)set(CMAKE_CXX_COMPILER ${ARM_TOOLCHAIN_PATH}/arm-poky-linux-gnueabi-g++)set(CMAKE_FIND_ROOT_PATH /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi/)set(CMAKE_SYSTEM_PROCESSOR arm)# 设置额外的编译标志set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -mfloat-abi=hard -mfpu=neon" CACHE STRING "" FORCE)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -mfloat-abi=hard -mfpu=neon" CACHE STRING "" FORCE)# 设置链接器set(CMAKE_LINKER ${CMAKE_C_COMPILER})set(CMAKE_AR ${ARM_TOOLCHAIN_PATH}/arm-poky-linux-gnueabi-ar)set(CMAKE_RANLIB ${ARM_TOOLCHAIN_PATH}/arm-poky-linux-gnueabi-ranlib)elseif(${TARGET_ARCH} STREQUAL "riscv")# RISC-V工具链配置 (C906核心)set(CMAKE_C_COMPILER ${RISCV_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-gcc)set(CMAKE_CXX_COMPILER ${RISCV_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-g++)set(CMAKE_FIND_ROOT_PATH ${RISCV_TOOLCHAIN_PATH}/riscv64-unknown-elf)set(CMAKE_SYSTEM_PROCESSOR riscv)# 设置RISC-V特定的编译标志 (C906核心)set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=rv64gcv0p7 -mabi=lp64d" CACHE STRING "" FORCE)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=rv64gcv0p7 -mabi=lp64d" CACHE STRING "" FORCE)# 设置链接器set(CMAKE_LINKER ${CMAKE_C_COMPILER})set(CMAKE_AR ${RISCV_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-ar)set(CMAKE_RANLIB ${RISCV_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-ranlib)else()message(FATAL_ERROR "不支持的目标架构: ${TARGET_ARCH}. 请使用 'arm' 或 'riscv'")
endif()# 设置查找规则
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)# 禁用系统库路径
set(CMAKE_SKIP_RPATH TRUE)# 设置交叉编译环境的库和头文件搜索路径
set(CMAKE_SYSROOT ${CMAKE_FIND_ROOT_PATH}) # 关键!!!,不能漏掉这个设置,如果需要安装到特定路径,特别是三方库安装需要到这里找依赖
set(CMAKE_FIND_ROOT_PATH /root/arm_install)

这个配置文件设置了目标系统的名称、处理器架构、工具链路径等重要信息。根据需要,我们可以选择编译针对ARM或RISC-V架构的库文件。

交叉编译Hiredis库

首先,我们需要交叉编译hiredis库,因为redis++是基于hiredis的。在项目根目录下创建一个build目录,并在其中执行以下命令:

cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DTARGET_ARCH=arm -DCMAKE_INSTALL_PREFIX=${HOME}/arm_install
make
make install

这样,hiredis库就会被交叉编译并安装到${HOME}/arm_install目录下。

交叉编译Redis++库

接下来,我们使用相同的工具链文件来交叉编译redis++。在redis++的源码目录下创建一个build目录,并在其中执行以下命令:

cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DTARGET_ARCH=arm -DCMAKE_INSTALL_PREFIX=${HOME}/arm_install -DCMAKE_PREFIX_PATH=${HOME}/arm_install -DREDIS_PLUS_PLUS_CXX_STANDARD=11 -DREDIS_PLUS_PLUS_BUILD_TEST=OFF
make
make install

这里,我们启用了C++11标准,并且关闭了测试功能,以加快编译速度。编译完成后,redis++库也会被安装到${HOME}/arm_install目录下。

使用Redis++库

下面是一个简单的示例代码,展示了如何使用redis++库。这个示例演示了如何连接到Redis服务器,并进行一些基本的操作,比如读取Hash数据结构中的内容。

#include <unistd.h>
#include <chrono>
#include <tuple>
#include <iostream>
#include <vector>
#include <map>
#include <unordered_set>
#include <sw/redis++/redis++.h>
#include <sw/redis++/sentinel.h>
#include <sw/redis++/connection.h>
#include <sw/redis++/connection_pool.h>using namespace sw::redis;
using namespace std::chrono;int main() {// 设置连接选项ConnectionOptions connection_options;connection_options.host = "192.168.11.85";  // 必需,Redis服务器地址connection_options.port = 16379; // 可选,默认端口是6379connection_options.db = 5;  // 可选,默认使用第0个数据库// 设置连接池选项ConnectionPoolOptions pool_options;pool_options.size = 3;  // 连接池大小,即最大连接数pool_options.wait_timeout = std::chrono::milliseconds(100);// 创建Redis连接实例Redis redis(connection_options, pool_options);// 使用hscan命令遍历Hash中的元素auto cursor = 0LL;auto pattern = "*";auto count = 5;std::map<std::string, std::string> hashs;while (true) {cursor = redis.hscan("FORWARD.PLAT.DETAIL", cursor, pattern, count, std::inserter(hashs, hashs.begin()));if (cursor == 0) {break;}}if(hashs.size() < 1) {printf("我们没有获取到任何数据!\n");} else {for(auto it1 = hashs.begin(); it1 != hashs.end(); it1++) {std::cout << "Plat ID:" << it1->first << std::endl;std::cout << "Plat UserName & Password:" << it1->second << std::endl;}}// 使用hget命令获取Hash中指定key的valueOptionalString strValue = redis.hget("XNY.CARINFO", "CRC01211711100232");if (strValue) {std::cout << "CRC01211711100232 的 vin:" << *strValue << std::endl;std::string straa = *strValue;if(straa.empty()) {std::cout << "我们没有获取到任何数据!" << std::endl;} else {std::cout << "---- CRC01211711100232 的 details:" << straa << std::endl;}} else {std::cout << "CRC01211711100232 的 vin 不存在!" << std::endl;}// 使用hincrby命令对Hash中的某个数值字段进行自增操作std::cout << "---- 下面我们来试试hincrby ---- " << std::endl;auto cursor2 = 0LL;auto pattern2 = "*";auto count2 = 20;std::map<std::string, std::string> vv;std::vector<std::string> vlist;while (true) {cursor2 = redis.hscan("FORWARD.LIST.002", cursor2, pattern2, count2, std::inserter(vv, vv.begin()));if (cursor2 == 0) {break;}}for(auto it1 = vv.begin(); it1 != vv.end(); it1++) {vlist.push_back(it1->first);}for(auto uu = vlist.begin(); uu != vlist.end(); uu++) {std::cout << *uu << std::endl;}return 0;
}

在这段代码中,我们首先设置了连接选项和连接池选项,然后创建了一个Redis对象。接着,我们使用hscan命令遍历了一个Hash数据结构中的所有元素,并使用hget命令获取了一个特定key的value。最后,我们尝试使用hincrby命令对一个数值字段进行了自增操作。

结论

通过使用redis++库,我们可以更方便地在嵌入式Linux系统中与Redis进行交互。它提供了丰富的功能和易于使用的接口,极大地方便了开发工作。希望这篇博文能够帮助到需要在嵌入式Linux系统中使用Redis的开发者。

相关文章:

  • 多物理场耦合低温等离子体装置求解器PASSKEy2
  • ROS 快速入门教程04
  • 【Vue】静态站点生成(VitePress)
  • 星火燎原:大数据时代的Spark技术革命在数字化浪潮席卷全球的今天,海量数据如同奔涌不息的洪流,传统的数据处理方式已难以满足实时、高效的需求。
  • 【Python数据库编程实战】从SQL到ORM的完整指南
  • 大数据分析04 数据查询分析
  • SAP接口超时:对 FOR ALL ENTRIES IN 的优化
  • 数字化转型的“暗礁“与突围:失败案例深度复盘
  • 常用浪涌保护器件的原理、特性与应用对比
  • 巧记英语四级单词 Unit5-上【晓艳老师版】
  • onloyoffice 服务器保存文件的时间 和 当前时间 相差八小时 如何改
  • 如何将 Apache Hudi 接入 Ambari?完整部署与验证指南
  • linux 部署express项目,并使用pm2守护进程
  • 鸿蒙-试一下属性字符串:除了Span之外,如何在同一个Text组件中展示不同样式的文字
  • Python教程(一)——Python速览
  • AIGC实战之如何构建出更好的大模型RAG系统
  • 电脑技巧:路由器内部元器件介绍
  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(11): てあります。
  • 算法题(134):地毯
  • Java 24 深度解析:云原生时代的性能更新与安全重构
  • 牛市早报|商务部:目前中美之间未进行任何经贸谈判
  • 国家发改委党组在《人民日报》发表署名文章:新时代新征程民营经济发展前景广阔大有可为
  • 何立峰出席跨境贸易便利化专项行动部署会并讲话
  • 上海天文馆加持,书友可在徐家汇书院“飞越银河系”!
  • 上海楼市明显复苏:一季度房地产开发投资增长5.1%,土地市场重燃战火
  • 何以中国|福建武夷山:千年茶道的文旅“破圈”与新生