项目中,有些数据由于环境限制无法实时传输,因此需要将这些数据保存下来,等待条件允许时再传输。redis数据库是一个key-value型的数据库,并且其数据实时保存在内存中,读写速度快,还可以自行配置将内存的数据写入到存储介质的时间间隔,满足实际使用要求。
由于项目采用的是TI am57xx芯片,因此,需要将redis源码交叉编译移植到板卡上。redis源码交叉编译与其他第三库移植,同样遵循make,make install两个步骤。redis源码采用的是redis-6.2.6.tar.bz2。这个编译redis不需要configure配置。
redis交叉编译移植
解压,执行下面语句即可。
make MALLOC=libc CC=arm-linux-gnueabihf-gcc
编译后如下所示:
在redis/src路径下,将会生成redis-server, redis-client 等可执行文件
其中,redis.conf在redis的源码目录下,读者需要将这些文件拷贝到板卡的/bin目录下,将redis.conf拷贝到/etc目录下即可。
然后在板卡上启动redis服务:
redis-server /etc/redis.conf &
启动redis客户端:
redis-client
redis的命令可以参考链接http://doc.redisfans.com/
redis的配置文件redis.conf
这里仅介绍常用的一些配置项:
60s至少改动一处即可保存(这里的保存是指真正写入存储介质,而不是停留在内存区)
配置数据库默认名称为dump.rdb
配置默认工作路径:/meida/mmc1p3
配置数据库默认容量:100MB
配置数据库的保存算法:
以上是此次项目中的常用配置,其他配置项读者可以自行查阅官方文档。
redis.conf更新后,需要将redis.conf重新拷贝到/etc目录下。
redis的c++封装
这里所说的c++封装,是指作者出于项目的需要,额外重新封装一些接口,内部依旧调用redis的c接口。redis源码自带了redis的c接口,因此,第一需要将这些c接口分离出来。这些c接口函数位于redis/deps/hiredis/目录下:
先建立一个redis_test目录,在redis_test路径下,再建立include以及src两个子目录;
将hiredis目录下的头文件拷贝到redis_test/include下:
将hiredis目录下的源文件拷贝到redis_test/src下:
注意:example.c、example.cpp以及build_redis_test.sh是自行编写的,后面会提到。拷贝过来的是redis的c接口函数,无需改动。
编写Redis类,Redis类根际实际使用对外只开放7个接口,分别为判断is_key_exists,设置单个key-valu值set_single_key,获取单个key-value值get_single_key,获取单个key-value并删除getdel_single_key,设置多个key-value值mset_multi_key,获取多个key-value值mget_multi_key,删除多个key值del_list。
每个接口内部,实际调用的依旧是hiredis的c接口,之所以封装,是为了隐去hiredis的实现步骤,读者可专注于使用逻辑。
完整的Redis类实现代码如下:
#include#include #include #include #include #include #include #include #include using namespace std; #define VALUE_BUFF_SIZE (512 * 20) struct st_key_val { string key; uint8_t buff[VALUE_BUFF_SIZE]; size_t buff_len; }; typedef list
ST_KEY_VAL_LIST; typedef list ST_KEY_LIST; class Redis { private: string hostname; int hostport; redisContext *context; struct timeval timeout; int hex2char(uint8_t *buff, int32_t len, string *out_str); int char2hex(char *in_str, int32_t in_str_len, uint8_t *out, int32_t out_len); public: long long is_key_exists(const string key); int set_single_key(const string key, uint8_t *buff, int32_t len); int get_single_key(const string key, uint8_t *buff, int32_t len); int getdel_single_key(const string key, uint8_t *buff, int32_t len); int mset_multi_key(ST_KEY_VAL_LIST key_val_list); //int mget_multi_key(const string key_list[], int32_t key_num, ST_KEY_VAL_LIST *val_list); int mget_multi_key(ST_KEY_LIST key_list, ST_KEY_VAL_LIST *val_list); //int del_list(const string key_list[], const int32_t key_num); int del_list(ST_KEY_LIST del_key_list); public: Redis(string name = "127.0.0.1", int port = 6379, int32_t sec = 1, int32_t microsec = 500000) { redisReply *reply; hostname = name; hostport = port; timeout = {sec, microsec}; context = redisConnectWithTimeout(hostname.c_str(), port, timeout); if ((context == NULL) || (context->err)) { if (context) { printf("Connection error: %sn", context->errstr); redisFree(context); } else { printf("Connection error: can't allocate redis contextn"); } exit(1); } reply = (redisReply *)redisCommand(context,"PING"); printf("PING: %sn", reply->str); freeReplyObject(reply); } }; long long Redis::is_key_exists(const string key) { redisReply *reply = NULL; long long integer = 0; const char *c_key = key.c_str(); reply = (redisReply *)redisCommand(context,"EXISTS %s", c_key); integer = reply->integer; freeReplyObject(reply); return integer; } int Redis::set_single_key(const string key, uint8_t *buff, int32_t len) { int32_t i = 0; redisReply *reply; const char *c_key = key.c_str(); string s_val; char aa[8]; //for (i = 0; i < len; i++) //{ // sprintf(aa, "%.2x", (uint8_t)buff[i]); // s_val += aa; //} hex2char(buff, len, &s_val); reply = (redisReply *)redisCommand(context,"SET %s %s", c_key, s_val.c_str()); printf("SET: %sn", reply->str); freeReplyObject(reply); return 1; } int Redis::get_single_key(const string key, uint8_t *buff, int32_t len) { redisReply *reply = NULL; char recv[len] = {' '}; int32_t recv_len = 0; const char *c_key = key.c_str(); memset(recv, 0x00, sizeof(recv)); if (is_key_exists(key) == 1) { reply = (redisReply *)redisCommand(context,"GET %s", c_key); if (reply != NULL) { strcpy(recv, reply->str); recv_len = char2hex(recv, reply->len, buff, len); freeReplyObject(reply); } } return recv_len; } int Redis::getdel_single_key(const string key, uint8_t *buff, int32_t len) { redisReply *reply = NULL; char recv[len] = {' '}; int32_t recv_len = 0; const char *c_key = key.c_str(); memset(recv, 0x00, sizeof(recv)); if (is_key_exists(key) == 1) { reply = (redisReply *)redisCommand(context,"GETDEL %s", c_key); if (reply != NULL) { strcpy(recv, reply->str); recv_len = char2hex(recv, reply->len, buff, len); freeReplyObject(reply); } } return recv_len; } int Redis::mset_multi_key(ST_KEY_VAL_LIST key_val_list) { redisReply *reply; ST_KEY_VAL_LIST::iterator st_key_val; string mset_str = "MSET"; for (st_key_val = key_val_list.begin(); st_key_val != key_val_list.end(); st_key_val++) { mset_str.append(" "); mset_str.append(st_key_val->key); mset_str.append(" "); string s_val; hex2char(st_key_val->buff, st_key_val->buff_len, &s_val); mset_str.append(s_val); } reply = (redisReply *)redisCommand(context, mset_str.c_str(), NULL); //printf("SET: %sn", reply->str); freeReplyObject(reply); } #if 0 int Redis::mget_multi_key(const string key_list[], const int32_t key_num, ST_KEY_VAL_LIST *val_list) { redisReply *reply; int32_t i = 0; struct st_key_val val; int32_t val_cn = 0; string mget_str = "MGET"; const char *c_mget_str = NULL; for (i = 0; i < key_num; i++) { mget_str.append(" "); mget_str.append(key_list[i]); } c_mget_str = mget_str.c_str(); reply = (redisReply *)redisCommand(context, c_mget_str, NULL); if (reply != NULL) { if (reply->elements > 0) { //printf("reply->elements = %dn", reply->elements); for (i = 0; i < reply->elements; i++) { val.key = key_list[i]; val.buff_len = char2hex(reply->element[i]->str, reply->element[i]->len, val.buff, VALUE_BUFF_SIZE); val_list->push_back(val); val_cn++; } } } freeReplyObject(reply); return val_cn; } #endif int Redis::mget_multi_key(ST_KEY_LIST key_list, ST_KEY_VAL_LIST *val_list) { redisReply *reply; int32_t i = 0; struct st_key_val val; int32_t val_cn = 0; string mget_str = "MGET"; const char *c_mget_str = NULL; ST_KEY_LIST::iterator mget_key; for (mget_key = key_list.begin(); mget_key != key_list.end(); mget_key++) { mget_str.append(" "); mget_str.append(*mget_key); } c_mget_str = mget_str.c_str(); reply = (redisReply *)redisCommand(context, c_mget_str, NULL); if (reply != NULL) { if (reply->elements > 0) { //printf("reply->elements = %dn", reply->elements); mget_key = key_list.begin(); for (i = 0; i < reply->elements; i++) { val.key = *mget_key; val.buff_len = char2hex(reply->element[i]->str, reply->element[i]->len, val.buff, VALUE_BUFF_SIZE); val_list->push_back(val); val_cn++; mget_key++; } } } freeReplyObject(reply); return val_cn; } #if 0 int Redis::del_list(const string key_list[], const int32_t key_num) { redisReply *reply; int32_t i = 0; const char *c_list_name; string del_str = "DEL"; for (i = 0; i < key_num; i++) { if (is_key_exists(key_list[i])) { del_str.append(" "); del_str.append(key_list[i]); } } c_list_name = del_str.c_str(); printf("c_list_name = %sn", c_list_name); reply = (redisReply *)redisCommand(context, c_list_name, NULL); printf("reply->integer = %lldn", reply->integer); freeReplyObject(reply); return 0; } #endif int Redis::del_list(ST_KEY_LIST del_key_list) { long long ret = 0; redisReply *reply; const char *c_list_name; string del_str = "DEL"; ST_KEY_LIST::iterator del_key; for (del_key = del_key_list.begin(); del_key != del_key_list.end(); del_key++) { if (is_key_exists(*del_key)) { del_str.append(" "); del_str.append(*del_key); } } c_list_name = del_str.c_str(); //printf("c_list_name = %sn", c_list_name); reply = (redisReply *)redisCommand(context, c_list_name, NULL); //printf("reply->integer = %lldn", reply->integer); ret = reply->integer; freeReplyObject(reply); return ret; } int Redis::hex2char(uint8_t *buff, int32_t len, string *out_str) { //uint8_t tmp = 0x00; //int32_t i = 0; //int32_t j = 0; //for (i = 0; i < len; i++) //{ // for (j = 0; j < 2; j++) // { // tmp = (*(buff + i) >> 4) * (1 - j) + (*(buff + i) & 0x0f) * j; // if ((tmp >= 0) && (tmp <= 9)) // { // val[2 * i + j] = tmp + '0'; // } // else if ((tmp >= 0x0A) && (tmp <= 0x0F)) // { // val[2 * i + j] = tmp - 0x0A + 'A'; // } // } //} //string s; //char aa[8]; //for(uint16_t i = 0; i < len; i++) //{ // sprintf(aa, "%.2x", (uint8_t)buff[i]); // s += aa; //} char aa[8]; for(uint16_t i = 0; i < len; i++) { sprintf(aa, "%.2x", (uint8_t)buff[i]); out_str->append(aa); } //printf("s = %sn", s.c_str()); return 0; } int Redis::char2hex(char *in_str, int32_t in_str_len, uint8_t *out, int32_t out_len) { char *p = in_str; uint8_t high = 0; uint8_t low = 0; int cnt = 0; int32_t ret_len = 0; while (cnt < in_str_len/2) { high = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; low = (*(++p) > '9' && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; out[cnt] = (high & 0x0f) << 4 | (low & 0x0f); p++; cnt++; } if (in_str_len % 2 != 0) { out[cnt] = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; } ret_len = in_str_len / 2 + in_str_len % 2; return ret_len; } int main(int argc, char *argv[]) { Redis xz_redis; uint8_t data[] = {0x01, 0x11, 0xa0, 0xff, 0x0f, 0x90}; uint8_t recv[1024];; int32_t recv_len = 0; int32_t i = 0; string del_key[] = {"xu"}; char val[8]; ST_KEY_VAL_LIST val_list; string mget_key[] = {"yc1", "yc2", "yc4", "yc3", "yc7", "yc6", "yc5"}; ST_KEY_VAL_LIST::iterator st_val; int32_t st_val_cn = 0; ST_KEY_VAL_LIST mset_list; struct st_key_val mset_val; mset_val.key = "yc5"; mset_val.buff[0] = 0x58; mset_val.buff[1] = 0x58; mset_val.buff[2] = 0x58; mset_val.buff[3] = 0x58; mset_val.buff_len = 4; mset_list.push_back(mset_val); mset_val.key = "yc6"; mset_val.buff[0] = 0x61; mset_val.buff[1] = 0x62; mset_val.buff[2] = 0x63; mset_val.buff[3] = 0x64; mset_val.buff_len = 4; mset_list.push_back(mset_val); mset_val.key = "yc7"; mset_val.buff[0] = 0x79; mset_val.buff[1] = 0x79; mset_val.buff[2] = 0x79; mset_val.buff[3] = 0x79; mset_val.buff_len = 4; mset_list.push_back(mset_val); ST_KEY_LIST del_key_list; for (i = 0; i < 7; i++) { del_key_list.push_back(mget_key[i]); } while(1) { xz_redis.mset_multi_key(mset_list); st_val_cn = xz_redis.mget_multi_key(del_key_list, &val_list); printf("st_val_cn = %dn", st_val_cn); for (st_val = val_list.begin(); st_val != val_list.end(); st_val++) { printf("st_val.key = %sn", st_val->key.c_str()); printf("st_val.buff_len = %dn", st_val->buff_len); for (i = 0; i < st_val->buff_len; i++) printf("st_val.buff[%d] = %xn", i, st_val->buff[i]); } xz_redis.del_list(del_key_list); //xz_redis.del_list(del_key, 1); //xz_redis.set_single_key("xu", data, sizeof(data)); //recv_len = xz_redis.get_single_key("xu", recv, sizeof(recv)); //if (recv_len > 0) //{ // printf("recv_len = %dn", recv_len); // for (i = 0; i < recv_len; i++) // printf("0x%.2x ", recv[i]); // printf("n"); //} //else //{ // printf("not existsn"); //} break; } }
读者在用上述例子测试时,可以按下面的方法交互测试:
用代码写入key-value,再用redis命令读取,验证是否正确;
用命令写入key-value,再用代码读取,验证是否正确;
注意:上述代码实现的例子,写入的数据均会转成字符串写入到redis中。但因为作者实际使用的数据均为uint8_t数组,因此还做了转换函数,但转换函数不对外开放。
完整的代码实现以及redis的编译资源见链接:https://download.csdn.net/download/qq_36731830/60825216



