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

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的开发者。

相关文章:

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

在开发过程中&#xff0c;我们经常会遇到需要在嵌入式Linux系统上与Redis进行交互的需求。因此选择一个适合的Redis客户端库就显得尤为重要。下面介绍下c中有名的redis-plus-plus&#xff08;redis&#xff09;三方库在嵌入式linux下的交叉编译及使用。该库底层是基于hiredis的…...

gitlab-ce容器镜像源(国内)

下载命令 docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/gitlab/gitlab-ce:17.10.4-ce.0 更多参考&#xff1a; https://docker.aityp.com/image/docker.io/gitlab/gitlab-ce:17.10.4-ce.0...

小白自学python第二天

学习python的第二天 一、判断语句 1、布尔类型和比较运算符 1、布尔类型 表示现实生活中的逻辑&#xff0c;真&#xff08;True&#xff0c;用数字1表示&#xff09;和假&#xff08;False&#xff0c;用数字0表示&#xff09; 2、布尔类型变量的定义 变量的名称 布尔类…...

嵌入式面试高频考点深度解析:内存管理、指针操作与结构体实战指南

试题一&#xff1a;大小端系统中数据的内存表现形式 题目 short tmp 0xaabb; 请分别写出大小端系统中&#xff0c;tmp 在内存中的表现形式。 分析 1. 什么是高位与低位&#xff1f; 对于一个数据而言&#xff0c;以十六进制数 0xaabb 为例&#xff0c;从左至右&#xff0…...

ApplicationRunner的run方法与@PostConstruct注解

ApplicationRunner 的 run 方法与 PostConstruct 注解在 Spring Boot 中均用于初始化逻辑&#xff0c;但二者的 执行时机、作用范围 和 功能特性 存在显著差异。以下是详细对比分析&#xff1a; 一、核心差异对比 维度PostConstructApplicationRunner.run()触发时机Bean 实例化…...

今日行情明日机会——20250425

指数依然在震荡&#xff0c;等待方向选择&#xff0c;整体量能不搞但个股红多绿少。 2025年4月25日涨停板行业方向分析如下&#xff1a; 一、核心行业方向及驱动逻辑 一季报增长&#xff08;17家涨停&#xff09; 核心个股&#xff1a;惠而浦、鸿博股份、卫星化学驱动逻辑&am…...

一道MySQL索引题

复合索引基础 MySQL中的复合索引(Composite Index)是指由多个列组成的索引。与单列索引不同、复合索引的结构更为复杂&#xff0c;但使用得当可以大幅提升查询性能。 复合索引的工作原理 复合索引的本质是一种有序的数据结、每个列是建立在那个索引前一列存在的情况下、那一…...

Python 读取 txt 文件详解 with ... open()

文章目录 1 概述1.1 注意事项1.2 模式说明1.3 文件准备 2 读文件2.1 读取整个文件2.2 逐行读取2.3 读取所有行到列表 3 写文件3.1 覆盖写入3.2 追加写入3.3 写入多行 4 实用技巧4.1 检查文件是否存在4.2 异常处理 1 概述 1.1 注意事项 文件编码&#xff1a;建议指定编码&…...

【linux】设置邮件发送告警功能

当服务器内存不足或者其他故障时&#xff0c;可以通过自动发送故障到邮箱进行提醒。 步骤&#xff1a; 以qq邮箱为例&#xff1a; 登录qq邮箱点击设置 点击账号后&#xff0c;往下翻 找到POP3/IMAP...开启服务 复制授权码 安装邮箱功能 编辑/etc/s-nail.rc 验证 …...

【手机】vivo手机应用声音分离方案

文章目录 前言方案 前言 尝试分离vivo手机音乐与其他应用的声音 方案 最佳方案&#xff1a;网易云音乐设置内关闭音量均衡 上传不同的白噪音&#xff0c;成功 goodlock&#xff0c;主要适用于三星手机&#xff0c;vivo不一定适用 app volume control &#xff0c;可行...

关于Safari浏览器在ios<16.3版本不支持正则表达式零宽断言的解决办法

异常原因 今天在升级Dify版本的时候发现低版本的ios手机出现了以下报错&#xff1a; SyntaxError: Invalid regular expression: invalid group specifier nameError: Invalid regular expression: invalid group specifier name Call Stack 46 eval [native code] (0:0) ./n…...

管理+技术”双轮驱动工业企业能源绿色转型

00序言 在“3060双碳”政策目标下&#xff0c;工业领域作为碳排放的主要来源&#xff08;占比约70%&#xff09;&#xff0c;国家出台《工业领域碳达峰实施方案》《加快推动制造业绿色化发展的指导意见》等文件&#xff0c;明确行业碳达峰时间表和重点任务&#xff0c;完善碳市…...

每天学一个 Linux 命令(30):cut

​​可访问网站查看,视觉品味拉满: http://www.616vip.cn/30/index.html cut 命令用于从文件或输入流中提取文本的特定部分(如列、字符或字节位置)。它常用于处理结构化数据(如 CSV、TSV)或按固定格式分割的文本。以下是详细说明和示例: 命令格式 cut [选项] [文件...]…...

智慧养老综合实训室规划与实施:产教融合的智慧养老实践

智慧养老综合实训室作为智慧养老、智慧康养产业发展的关键支撑&#xff0c;深度融合物联网、大数据、人工智能等前沿技术&#xff0c;搭建虚实结合的教学场景&#xff0c;依托DeepSeek知识库模型实现知识的高效转化与创新&#xff0c;旨在打造产教融合的实践平台&#xff0c;为…...

华为设备命令部分精简分类汇总示例

华为网络设备的命令体系庞大且复杂&#xff0c;不同设备系列&#xff08;如交换机、路由器、防火墙&#xff09;和不同操作系统版本&#xff08;如VRP5、VRP8&#xff09;的命令可能存在差异。以下是一个 精简分类汇总&#xff0c;涵盖常用配置场景和命令示例&#xff1a; 一、…...

JAVA | 聚焦 OutOfMemoryError 异常

个人主页 文章专栏 在正文开始前&#xff0c;我想多说几句&#xff0c;也就是吐苦水吧…最近这段时间一直想写点东西&#xff0c;停下来反思思考一下。 心中万言&#xff0c;真正执笔时又不知先写些什么。通常这个时候&#xff0c;我都会随便写写&#xff0c;文风极像散文&…...

Operating System 实验二 内存管理实验

目录 实验目标: 实验设备: 实验内容: (1)验证FIFO和Stack LRU页面置换算法 【代码(注释率不低于30%)】 【实验过程(截图)】 【结论】 (2)分别用FIFO和Stack LRU页置换算法,自己设定一个页面引用序列,绘制页错误次数和可用页帧总数的曲线并对比(可用Excel绘…...

CF-Hero:自动绕过CDN找真实ip地址

CF-Hero&#xff1a;自动绕过CDN找真实ip地址 CF-Hero 是一个全面的侦察工具&#xff0c;用于发现受 Cloudflare 保护的 Web 应用程序的真实 IP 地址。它通过各种方法执行多源情报收集。目前仅支持Cloudflare的cdn服务查找真实ip&#xff0c;但从原理上来说查找方法都是通用的…...

Linux基础IO(十一)之动态库(基础IO的最后一篇啦!)

文章目录 动态库生成动态库使用动态库现象事实使用外部库动态库怎么被加载的进程地址空间的第二讲关于地址1.程序没有加载前的地址&#xff08;程序&#xff09;2.程序加载后的地址&#xff08;进程&#xff09;3.动态库的地址 动态库 生成动态库 shared: 表示生成共享库格式…...

【版本控制】SVN + TortoiseSVN版本管理实用教程(附安装+开发常用操作)

摘要&#xff1a; 本文将带你从零开始掌握 SVN 版本控制系统&#xff0c;结合 TortoiseSVN 图形客户端工具&#xff0c;深入学习包括安装、检出、提交、更新、回滚、冲突解决等常用开发操作&#xff0c;快速上手团队协作&#xff01; &#x1f9e9; 什么是 SVN&#xff1f; SV…...

非序列实现MEMS聚焦功能

zemax非序列模式下有MEMS,但是没有对应的代码。无法修改成自己需要的功能 以下是实现MEMS聚焦功能: #include <windows.h> #include <cmath> #include <stdio.h> #include <string.h> #include <algorithm> #undef max #undef min#define D…...

【前端】CSS 基础

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解 CSS 基础语法。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff1a;前端基础…...

【金仓数据库征文】——选择金仓,选择胜利

目录 第一部分&#xff1a;金仓数据库——开创数据库技术的新时代 1.1 金仓数据库的技术底蕴 1.2 高可用架构与灾备能力 1.3 分布式架构与弹性扩展能力 第二部分&#xff1a;金仓数据库助力行业数字化转型 2.1 电信行业&#xff1a;核心系统国产化替代 2.2 医疗行业&…...

跟着尚硅谷学vue-day5

计算属性和watch监视 一.姓名案例 1.姓名案例-插值语法 <div id"root">姓&#xff1a;<input type"text" value"张" v-model"firstname"><br/><br/>名&#xff1a;<input type"text" value&q…...

【C到Java的深度跃迁:从指针到对象,从过程到生态】第四模块·Java特性专精 —— 第十三章 异常处理:超越C错误码的文明时代

一、错误处理的范式革命 1.1 C错误处理的黑暗时代 C语言通过返回值传递错误状态&#xff0c;存在系统性缺陷&#xff1a; 典型错误处理模式&#xff1a; FILE* open_file(const char* path) { FILE* f fopen(path, "r"); if (!f) { return NULL; // 错误信息…...

运维打铁:Centos 7 使用yum安装 mysql5.7

文章目录 一、安装前信息说明二、安装步骤1. 下载并安装官网 RPM 安装包2. 修改配置文件 /etc/my.cnf3. 创建 MySQL 数据相关目录并授权4. 启动 MySQL 服务 三、修改数据库访问密码1. 修改配置文件 /etc/my.cnf2. 重启 MySQL 服务3. 登录数据库并修改密码4. 恢复配置文件并重启…...

网络原理初始

基础概念 组建局域网方式&#xff1a;路由器或者交换机。 IP确定主机&#xff0c;端口号确定使用的应用程序。 端口号&#xff1a;每个程序在进行网络通信中&#xff0c;都需要一个端口号。 协议&#xff1a;通信过程中的约定。 TCP/IP五层网络协议 从上到下 1、应用层&a…...

基于SpringBoot3实现MyBatis-Plus(SSMP)整合快速入门CURD(增删改查)

目录 一、快速搭建SpringBoot-Web工程脚手架。 1.1 Spring Initializr 初始化工程。(官方提供) 1.2 工程脚手架初始化详细步骤。(IDEA2024.1.1) 二、MyBatis-Plus的特性与快速上手。 2.1 官网地址与基本特性。 2.2 快速上手技术栈基础。 2.3 Spring Boot2 的 MyBatis-Plus Star…...

主题模型三大基石:Unigram、LSA、PLSA详解与对比

&#x1f31f; 主题模型演进图谱 文本建模三阶段&#xff1a; 词袋模型 → 潜在语义 → 概率生成 Unigram → LSA → PLSA → LDA &#x1f4e6; 基础模型&#xff1a;Unigram模型 核心假设 文档中每个词独立生成&#xff08;词袋假设&#xff09; 忽略词语顺序和语义关联 …...

Redis 热 key 和大 key 问题

一、什么是 Redis 热 key&#xff1f; 热 key&#xff08;Hot Key&#xff09;定义&#xff1a; 在单位时间内被**频繁访问&#xff08;读/写&#xff09;**的 key&#xff0c;导致其访问集中、压力过大。 热 key 常见表现&#xff1a; QPS 极高&#xff08;某 key 每秒被访问…...