Redis是一个NoSQL数据库,本文将实现一个用c++ API接口连接的例子,来实现对Redis数据库的写入和读出功能,具体将从Redis的安装,Redis的c++接口hiredis安装,代码演示三部分组成。
一、Redis的安装和配置
由于源中已有Redis的相关组件,这里就不进行源码编译而直接使用apt-get (ubuntu环境)下载和安装
1.redis的安装和配置 sudo apt-cache search redis //根据结果列表找到需要安装的软件包:redis-server sudo apt-get install redis-server //安装软件 2.配置文件 whereis resids //查看redis位置: /etc/redis cd /etc/redis //进入文件夹 /etc/redis$ ls -l //显示文件,其中redis.conf为配置文件 总用量 60 -rw-r----- 1 redis redis 41623 12月 19 2015 redis.conf drwxr-xr-x 2 root root 4096 9月 21 10:47 redis-server.post-down.d drwxr-xr-x 2 root root 4096 9月 21 10:47 redis-server.post-up.d drwxr-xr-x 2 root root 4096 9月 21 10:47 redis-server.pre-down.d drwxr-xr-x 2 root root 4096 9月 21 10:47 redis-server.pre-up.d 3.启动 服务端:redis-server (使用默认端口) (--port 6599 加端口) 客户端:redis-cli (连接之前测试启动指令 redis-cli ping 返回PONG启动成功) 4.关闭:redis-cli (-p 6380 可指定端口)shutdown
二、redis的c++api接口 hiredis安装
实际上hiredis是一个c的接口,同样使用apt-get安装hiredis,GitHub上有他的完整工程项目,点此转到。
sudo apt-cache search hiredis // 查看发现c语言开发库为libhiredis-dev libhiredis-dbg - minimalistic C client library for Redis (debug) libhiredis-dev - minimalistic C client library for Redis (development files) libhiredis0.13 - minimalistic C client library for Redis python-hiredis - redis protocol reader for Python 2.X using hiredis sudo apt-get install libhiredis-dev //选择并安装
hiredis库目录的位置为默认的 /usr/lib/x86_64-linux-gnu/下,头文件在 /usr/include/hiredis 下,hiredis头文件中定义了Redis的连接的方式redisConnect()等方法,连接信息存储在上下文redisContext的结构体对象中,通过redisCommand()等方法进行具体的数据库存取指令操作并返回相关信息在redisReply的结构体对象中,不要忘了freeReplyObject(void *reply)释放redisReply连接响应对象,redisFree()函数释放redisContext上下文对象,具体的定义和方法请看以下代码。
#ifndef __HIREDIS_H #define __HIREDIS_H #include "read.h" #include
/* for va_list */ #include
/* for struct timeval */ #include
/* uintXX_t, etc */ #include "sds.h" /* for sds */ #define HIREDIS_MAJOR 0 #define HIREDIS_MINOR 13 #define HIREDIS_PATCH 3 #define HIREDIS_SONAME 0.13 #ifdef __cplusplus extern "C" { #endif /* This is the reply object returned by redisCommand() 执行redis数据库指令操作的响应信息封装在redisReply的结构体中 */ typedef struct redisReply { int type; /* REDIS_REPLY_* */ long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ int len; /* Length of string 存储字符串长度 */ char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING 错误信息和返回的string类型*/ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY 如果为数组存储数组长度*/ struct redisReply element; /* elements vector for REDIS_REPLY_ARRAY 存储数组元素向量*/ } redisReply; redisReader *redisReaderCreate(void); /* Function to free the reply objects hiredis returns by default. 释放响应对象 */ void freeReplyObject(void *reply); /* Functions to format a command according to the protocol. 数据库操作相关语句 */ int redisvFormatCommand(char target, const char *format, va_list ap); int redisFormatCommand(char target, const char *format, ...); int redisFormatCommandArgv(char target, int argc, const char argv, const size_t *argvlen); int redisFormatSdsCommandArgv(sds *target, int argc, const char argv, const size_t *argvlen); void redisFreeCommand(char *cmd); void redisFreeSdsCommand(sds cmd); enum redisConnectionType { REDIS_CONN_TCP, REDIS_CONN_UNIX, }; /* Context for a connection to Redis 建立上下文连接对象的结构体 */ typedef struct redisContext { int err; /* Error flags, 0 when there is no error错误标志,0表示没有错误 */ char errstr[128]; /* String representation of error when applicable 错误声明 */ int fd; int flags; char *obuf; /* Write buffer */ redisReader *reader; /* Protocol reader */ enum redisConnectionType connection_type; struct timeval *timeout; //设置连接等待时间 struct { char *host; char *source_addr; int port; } tcp; struct { char *path; } unix_sock; } redisContext; //建立上下文连接 redisContext *redisConnect(const char *ip, int port); redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); redisContext *redisConnectNonBlock(const char *ip, int port); redisContext *redisConnectBindNonBlock(const char *ip, int port, const char *source_addr); redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, const char *source_addr); redisContext *redisConnectUnix(const char *path); redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); redisContext *redisConnectUnixNonBlock(const char *path); redisContext *redisConnectFd(int fd); / * Reconnect the given context using the saved information. * * This re-uses the exact same connect options as in the initial connection. * host, ip (or path), timeout and bind address are reused, * flags are used unmodified from the existing context. * * Returns REDIS_OK on successfull connect or REDIS_ERR otherwise. */ int redisReconnect(redisContext *c); int redisSetTimeout(redisContext *c, const struct timeval tv); int redisEnableKeepAlive(redisContext *c); void redisFree(redisContext *c); int redisFreeKeepFd(redisContext *c); int redisBufferRead(redisContext *c); int redisBufferWrite(redisContext *c, int *done); /* In a blocking context, this function first checks if there are unconsumed * replies to return and returns one if so. Otherwise, it flushes the output * buffer to the socket and reads until it has a reply. In a non-blocking * context, it will return unconsumed replies until there are no more. */ int redisGetReply(redisContext *c, void reply); int redisGetReplyFromReader(redisContext *c, void reply); /* Write a formatted command to the output buffer. Use these functions in blocking mode * to get a pipeline of commands. */ int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); /* Write a command to the output buffer. Use these functions in blocking mode * to get a pipeline of commands. */ int redisvAppendCommand(redisContext *c, const char *format, va_list ap); int redisAppendCommand(redisContext *c, const char *format, ...); int redisAppendCommandArgv(redisContext *c, int argc, const char argv, const size_t *argvlen); /* Issue a command to Redis. In a blocking context, it is identical to calling * redisAppendCommand, followed by redisGetReply. The function will return * NULL if there was an error in performing the request, otherwise it will * return the reply. In a non-blocking context, it is identical to calling * only redisAppendCommand and will always return NULL. */ void *redisvCommand(redisContext *c, const char *format, va_list ap); void *redisCommand(redisContext *c, const char *format, ...); void *redisCommandArgv(redisContext *c, int argc, const char argv, const size_t *argvlen); #ifdef __cplusplus } #endif #endif
在read.h文件中有redisReply结构体宏的定义,int type的类型:
#ifndef __HIREDIS_READ_H #define __HIREDIS_READ_H #define REDIS_ERR -1 #define REDIS_OK 0 #define REDIS_ERR_IO 1 /* Error in read or write */ #define REDIS_ERR_EOF 3 /* End of file */ #define REDIS_ERR_PROTOCOL 4 /* Protocol error */ #define REDIS_ERR_OOM 5 /* Out of memory */ #define REDIS_ERR_OTHER 2 /* Everything else... */ #define REDIS_REPLY_STRING 1 //存放在char *str #define REDIS_REPLY_ARRAY 2 #define REDIS_REPLY_INTEGER 3 //integer存储为数据条数 #define REDIS_REPLY_NIL 4 #define REDIS_REPLY_STATUS 5 //成功状态码为:"OK" 存放在char *str #define REDIS_REPLY_ERROR 6 //存放在char *str

如hiredis.c文件中看freeReplyObject函数对以上响应状态的处理:
/* Free a reply object redisReply的类型有:REDIS_REPLY_INTEGER: REDIS_REPLY_ERROR: REDIS_REPLY_STATUS: REDIS_REPLY_STRING:这三个都是返回字符串 */ void freeReplyObject(void *reply) { redisReply *r = reply; size_t j; if (r == NULL) return; switch(r->type) { case REDIS_REPLY_INTEGER: break; /* Nothing to free */ case REDIS_REPLY_ARRAY: if (r->element != NULL) { for (j = 0; j < r->elements; j++) freeReplyObject(r->element[j]); free(r->element); } break; case REDIS_REPLY_ERROR: case REDIS_REPLY_STATUS: case REDIS_REPLY_STRING: free(r->str); break; } free(r); }
三、Redis使用hiredis API连接
代码结构如图所示:

具体代码如下:配置文件
#ifndef REDISCONFIG_H #define REDISCONFIG_H #include
class RedisConfig { public: RedisConfig(); std::string getRedisIP();//获取ip int getRedisPort();//获取端口号 }; #endif
#include "RedisConfig.h" #include
RedisConfig::RedisConfig() { } std::string RedisConfig::getRedisIP() { return "127.0.0.1";//设置为本机ip } int RedisConfig::getRedisPort() { return 6379; }
具体处理代码:包含了string类型和list类型的存取代码,根据redisReply响应的信息来进行信息的处理,对于其他类型对响应状态的判断可以通过命令行操作来确定,如图1所示。
#ifndef _H_REDIS_TOOLS_ #define _H_REDIS_TOOLS_ #include
#include
#include
#include
using namespace std; class RedisTool { public: RedisTool(); ~RedisTool(); int setString(string key, string value); string getString(string key); int setList(string key,vector
value); vector
getList(string key); private: void init(); redisContext *m_redis; RedisConfig m_config; }; #endif
#include
#include
#include
#include
#include
RedisTool::RedisTool() { m_redis = NULL; init(); } RedisTool::~RedisTool() { if(m_redis != NULL) { redisFree(m_redis);//析构函数释放资源 cout << "~RedisTool :: free redis connection " << endl; } } void RedisTool::init() { struct timeval timeout = { 1, }; // 1.5 seconds 设置连接等待时间 char ip[255]; strcpy(ip, m_config.getRedisIP().c_str()); cout << "init : ip = " << ip << endl; m_redis = redisConnectWithTimeout(ip, m_config.getRedisPort(), timeout);//建立连接 if (m_redis->err) { printf("RedisTool : Connection error: %s\n", m_redis->errstr); } else { cout << "init redis tool success " << endl; //REDIS_REPLY响应的类型type cout << "#define REDIS_REPLY_STRING 1"<< endl; cout << "#define REDIS_REPLY_ARRAY 2"<< endl; cout << "#define REDIS_REPLY_INTEGER 3"<< endl; cout << "#define REDIS_REPLY_NIL 4"<< endl; cout << "#define REDIS_REPLY_STATUS 5"<< endl; cout << "#define REDIS_REPLY_ERROR 6"<< endl; } } //向数据库写入string类型数据 int RedisTool::setString(string key, string value) { if(m_redis == NULL || m_redis->err)//int err; /* Error flags, 错误标识,0表示无错误 */ { cout << "Redis init Error !!!" << endl; init(); return -1; } redisReply *reply; reply = (redisReply *)redisCommand(m_redis,"SET %s %s", key.c_str(), value.c_str());//执行写入命令 cout<<"set string type = "<
type<
str = NULL " << endl; //pthread_spin_unlock(&m_redis_flock); return -1; } else if(strcmp(reply->str, "OK") == 0)//根据不同的响应类型进行判断获取成功与否 { result = 1; } else { result = -1; cout << "set string fail :" << reply->str << endl; } freeReplyObject(reply);//释放响应信息 return result; } //从数据库读出string类型数据 string RedisTool::getString(string key) { if(m_redis == NULL || m_redis->err) { cout << "Redis init Error !!!" << endl; init(); return NULL; } redisReply *reply; reply = (redisReply *)redisCommand(m_redis,"GET %s", key.c_str()); cout<<"get string type = "<
type<
len <= 0) { freeReplyObject(reply); return NULL; } else { stringstream ss; ss << reply->str; freeReplyObject(reply); return ss.str(); } } //向数据库写入vector(list)类型数据 int RedisTool::setList(string key,vector
value) { if(m_redis == NULL || m_redis->err) { cout << "Redis init Error !!!" << endl; init(); return -1; } redisReply *reply; int valueSize = value.size(); int result = 0; for(int i=0; i
integer; if(reply == NULL) { redisFree(m_redis); m_redis = NULL; result = -1; cout << "set list fail : reply->str = NULL " << endl; //pthread_spin_unlock(&m_redis_flock); return -1; } else if(reply->integer == old++) { result = 1; cout<<"rpush list ok"<
integer = " << reply->integer << endl; return -1; } } freeReplyObject(reply); cout<<"set List success"<
RedisTool::getList(string key) { if(m_redis == NULL || m_redis->err) { cout << "Redis init Error !!!" << endl; init(); return vector
{};//返回空的向量 } redisReply *reply; reply = (redisReply*)redisCommand(m_redis,"LLEN %s", key.c_str()); int valueSize = reply->integer; cout<<"List size is :"<
integer<
main函数:
#include
#include
#include
using namespace std; int main() { RedisTool redis; //测试 string redis.setString("wangbaojia","test1"); string result = redis.getString("wangbaojia"); cout<<"result="<
vec ={1,2,3,4}; redis.setList("bao",vec); vector
vecResult = redis.getList("bao"); for(int i=0;i
运行结果:

四、完整代码下载
点击下载
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/228165.html原文链接:https://javaforall.net
