C++ Redis mset 二进制数据接口封装方案
C++ Redis mset 二进制数据接口封装方案
需求
C++中使用hiredis客户端接口访问redis;
需要使用mset一次设置多个二进制数据
以下给出三种封装实现方案;
简单拼接方案
在redis-cli中,mset的语法是这样的:
/opt/colin$./redis-cli mset a 11 b 22 c 333
OK
按照这样的语法拼接后,直接使用hiredis字符串接口redisCommand传递:
void msetNotBinary(redisContext *c, const vector<string> &vtKey, const vector<string> & vtVal )
{
if(vtKey.size() != vtVal.size())
{
throw runtime_error( "Redis error" );
}
string strCmd = "MSET";
for(int i = 0; i < vtKey.size(); i++)
{
strCmd += " "+vtKey[i]+" "+vtVal[i];
}
cout << "strCmd:" << strCmd << endl;
void * r = redisCommand(c, strCmd.c_str() );
if ( !r )
throw runtime_error( "Redis error" );
freeReplyObject( r );
}
void do_test( redisContext *c )
{
vector<string> vtKey;
vector<string> vtVal;
vtKey.push_back("A");
vtVal.push_back("AAAA");
vtKey.push_back("B");
vtVal.push_back("BBBB");
vtKey.push_back("C");
vtVal.push_back("CCCC");
//add a binary data
vtKey.push_back("D");
vtVal.push_back("");
char a[] = "ABCDE";
a[2] = 0;
vtVal[3].assign(a,5);
try
{
msetNotBinary(c, vtKey, vtVal );
//mset1( c, vtKey, vtVal );
//mset2( c, vtKey, vtVal );
}
catch ( runtime_error & )
{
cout << "Error" << endl;
}
}
int main(int argc, char *argv[])
{
redisContext *c;
c = redisConnect("127.0.0.1",6379);
if (c->err)
{
cout << "Connection error: " << c->errstr << endl;
return -1;
}
do_test(c);
redisFree(c);
return 0;
}
这种方式可以处理mset多个字符串数据,但对于数据内容为二进制数据的无能为力;
redisCommandArgv接口传递 方案
对于多个参数传递,hiredis提供了以下接口,这个接口中最后一个参数是所有的传入数据的内容长度,
就是说这个接口是二进制安全的:
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
主要工作就是构造一个动态的二维数组char ** argv,其中涉及到char **到const char **的转换,有一定的风险,
关于这一点前一篇文章已经谈到;
void mset1( redisContext *c, const vector<string> &vtKey, const vector<string> & vtVal )
{
if(vtKey.size() != vtVal.size())
{
throw runtime_error( "Redis error" );
}
char ** argv = new char*[vtKey.size() + vtVal.size() + 1 ];
size_t * argvlen = new size_t[vtKey.size() + vtVal.size() + 1 ];
int j = 0;
argv[j] = new char[5];
memcpy(argv[j],"MSET",4);
argvlen[j] = 4;
++j;
for(int i = 0 ; i < vtKey.size();i++)
{
argvlen[j] = vtKey[i].length();
argv[j] = new char[argvlen[j]];
memset((void*)argv[j],0,argvlen[j] );
memcpy((void*)argv[j],vtKey[i].data(),vtKey[i].length());
j++;
argvlen[j] = vtVal[i].length();
argv[j] = new char[argvlen[j]];
memset((void*)argv[j],0,argvlen[j]);
memcpy((void*)argv[j],vtVal[i].data(),vtVal[i].length());
j++;
}
//if not use const_cast<const char**> ,compile error
//for why assign from char** to const char** error, see my blog ...
void *r = redisCommandArgv(c, vtKey.size() + vtVal.size() + 1, const_cast<const char**>(argv), argvlen );
if ( !r )
throw runtime_error( "Redis error" );
freeReplyObject( r );
for(int i = 0;i < vtKey.size();i++)
{
delete [] argv[i];
argv[i] = NULL;
}
delete []argv;
delete []argvlen;
argv = NULL;
}
redisCommandArgv接口传递的Vector方案
还是使用redisCommandArgv接口,使用vector来构造这个const char **,这个方法是从参考资料1中学到的:
void mset2( redisContext *c, const vector<string> &vtKey, const vector<string> & vtVal)
{
if(vtKey.size() != vtVal.size())
{
throw runtime_error( "Redis error" );
}
vector<const char *> argv( vtKey.size() + vtVal.size() + 1 );
vector<size_t> argvlen( vtKey.size() + vtVal.size() + 1 );
int j = 0;
static char msetcmd[] = "MSET";
argv[j] = msetcmd;
argvlen[j] = sizeof(msetcmd)-1;
++j;
for(int i = 0;i< vtKey.size();++i)
{
argvlen[j] = vtKey[i].length();
argv[j] = new char[argvlen[j]];
memset((void*)argv[j],0,argvlen[j] );
memcpy((void*)argv[j],vtKey[i].data(),vtKey[i].length());
j++;
argvlen[j] = vtVal[i].length();
argv[j] = new char[argvlen[j]];
memset((void*)argv[j],0,argvlen[j]);
memcpy((void*)argv[j],vtVal[i].data(),vtVal[i].length());
j++;
}
void *r = redisCommandArgv(c, argv.size(), &(argv[0]), &(argvlen[0]) );
for(int i = 0; i < argv.size();i++)
{
delete argv[i];
argv[i] = NULL;
}
if ( !r )
throw runtime_error( "Redis error" );
freeReplyObject( r );
}
这样,就实现二进制数据的传递;
二进制校验
程序执行后,可以用redis-cli来验证:
对于非二进制安全的实现,二进制内容是截断的:
/opt/app/colin$./redis-cli get D
"AB"
而二进制安全的实现接口,二进制数据的0通过转义方式显示:
/opt/app/colin$./redis-cli get D
"AB\x00DE"
完整可执行的代码详见github:https://github.com/me115/cppset/tree/master/2DimArray
参考资料
https://gist.github.com/dspezia/1455082
Posted by: 大CC | 8JAN,2015
博客:blog.me115.com [订阅]
微博:新浪微博
C++ Redis mset 二进制数据接口封装方案的更多相关文章
- Redis客户端Java服务接口封装
最近在学习Redis并集成到Spring中去,发现Spring的RedisTemplate并不好用,还没有MongoTemplate好用. 而且发现Jedis和ShardedJedis的方法非常多,覆 ...
- Sword redis存取二进制数据
#include "hiredis/hiredis.h" /* redis头文件 */ #include <stdio.h> #include <stdlib.h ...
- redis集群数据迁移
redis集群数据备份迁移方案 n 迁移环境描述及分析 当前我们面临的数据迁移环境是:集群->集群. 源集群: 源集群为6节点,3主3备 主 备 192.168.112.33:8001 192 ...
- StackExchange.Redis帮助类解决方案RedisRepository封装(字符串类型数据操作)
本文版权归博客园和作者本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/tag/NoSql/ 目录 一.基础配置封装 二.String字符串类型数据操作封 ...
- Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析
mongodb和memcached不是一个范畴内的东西.mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据.mongodb和memcached不存在谁替换谁的问题. 和 ...
- redis 数据备份持久化方案
本文链接:http://www.cnblogs.com/zhenghongxin/p/9050219.html 使用两种备份方案 备份方案选择RDB和AOF同时进行备份,必须打开AOF的持久化机制,除 ...
- Redis 数据持久化的方案的实现
原文:Redis 数据持久化的方案的实现 版权声明:m_nanle_xiaobudiu https://blog.csdn.net/m_nanle_xiaobudiu/article/details/ ...
- 在这个应用中,我使用了 MQ 来处理异步流程、Redis 缓存热点数据、MySQL 持久化数据,还有就是在系统中调用另外一个业务系统的接口,对我的应用来说这些都是属于 RPC 调用,而 MQ、MySQL 持久化的数据也会存在于一个分布式文件系统中,他们之间的调用也是需要用 RPC 来完成数据交互的。
在这个应用中,我使用了 MQ 来处理异步流程.Redis 缓存热点数据.MySQL 持久化数据,还有就是在系统中调用另外一个业务系统的接口,对我的应用来说这些都是属于 RPC 调用,而 MQ.MySQ ...
- JAVAEE——宜立方商城06:Redis安装、数据类型和持久化方案、Redis集群分析与搭建、实现缓存和同步
1. 学习计划 1.首页轮播图展示 2.Redis服务器搭建 3.向业务逻辑中添加缓存. 4.使用redis做缓存 5.缓存同步. 2. 首页轮播图动态展示 2.1. 功能分析 根据分类id查询内容列 ...
随机推荐
- mysql笔记04 MySQL高级特性
MySQL高级特性 1. 分区表:分区表是一种粗粒度的.简易的索引策略,适用于大数据量的过滤场景.最适合的场景是,在没有合适的索引时,对几个分区进行全表扫描,或者是只有一个分区和索引是热点,而且这个分 ...
- Oracle读书笔记
数据区(也叫数据扩展区)由一组连续的Oracle块所构成的Oracle存储结构,一个或多个数据块组成一个数据区,一个或多个数据区再组成一个断(Segment). 数据块是Oracle逻辑存储中的最小的 ...
- 解析XML的四种方式
四种操作xml的方式: SAX, DOM, JDOM , DOM4J的比较 1. 介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官 ...
- React笔记_(3)_react语法2
React笔记_(3)_react语法2 state和refs props就是在render渲染时,向组件内传递的变量,这个传递是单向的,只能继承下来读取. 如何进行双向传递呢? state (状态机 ...
- sersync实现触发式同步
金山的一个居于inotify+rsync进行二次开发实现文件同步的小工具sersync,能够很方便的实现文件触发式同步 Inotify 是基于inode级别的文件系统监控技术,是一种强大的.细粒度的. ...
- fedora 20 yum出错
需要利用linux做项目,所以在win10装了vmvare 以及 fedora,据说这个linux比较稳定.. 1.系统装好以后,需要先把terminal调处理,这才符合程序猿的习惯嘛,具体方法如下 ...
- Binary Tree Level Order Traversal II
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...
- Microsoft Office 2013 Product Key
Microsoft Office 2013 Product Key ( Professional Plus ) PGD67-JN23K-JGVWW-KTHP4-GXR9G B9GN2-DXXQC-9D ...
- Ubuntu 14.04 安装 JDK 7.0
1.新建jvm文件夹-解压 # mkdir /usr/lib/jvm # tar zxvf jdk-7u79-linux-x64.gz -C /usr/lib/jvm 2.设置环境变量,在/etc/p ...
- Window下memcached安装与测试步骤
如何在Window下memcached安装与测试步骤 工具/原料 电脑 memcached 软件 方法/步骤 软件包下载 下载Memercached For Windows:http://downlo ...