1)hiredis使用了Win32_Interop一个库,这个库写的贼乱,导致与ws2_32.lib中的函数冲突,没有办法只能重新封装一个DLL,在其他的项目中使用DLL来处理;

2)hiredis本身非线程安全,所以多个线程需要使用连接池来操作;

3)hiredis默认使用MTD库,应该在c++---->代码生成的位置改为MDD库;

4)  我也不知道redis客户端多久会被被超时替出来,所以需要使用ping命令检测一下是否重连;

首先我们随便封装一下基础代码:RedisClient

RedisClient.h

#pragma once#include <stdio.h>
#include <hiredis/hiredis.h>
#include <iostream>
#include <string>
//#include <WinSock2.h>//#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "hiredis.lib")
#pragma comment(lib, "Win32_Interop.lib")
#include <sstream>
#include <vector>
#include <map>
#include "CharVector.h"namespace robin
{class RedisClient{public:RedisClient() : getReply(nullptr){}~RedisClient() {Close();printf("~RedisClient() \n");}bool isConnOk();bool Reconnect();bool Conn(const char * ip, int port = 6379);void Close();int  checkError();size_t SetHValue(std::string & table, std::string & field, const char * value, size_t len);size_t SetHValue(std::string & table, std::string & field, std::string & value);int64_t INCR(std::string & table, std::string & field, int count);size_t QueryKeys(std::string & table, std::vector<std::string>& vec);size_t QueryKeys(std::string & table, std::map<uint32_t, string>& map);size_t Query(std::string & table, std::string & field, std::string & value);size_t Query(std::string & table, std::string & field, CharVector & value);size_t QueryCount(string & table);//size_t SetHValue(const char * table, const char *  field, const char * value, size_t len);size_t Query(const char * table, const char * field, char ** pValue);size_t QueryCount(const char * table);int64_t INCR(const char * table, const char * field, int count);//CharVector buffer;private:redisContext* conn = nullptr;std::string _ip;int _port;redisReply * getReply;  // used for get};}

RedisClient.cpp

#include "RedisClient.h"
//#include <winsock.h>
//#include <winsock2.h>
using namespace robin;#ifndef _WIN32
#include <sys/time.h> /* for struct timeval */
#else
//struct timeval {
//  long    tv_sec;         /* seconds */
//  long    tv_usec;        /* and microseconds */
//};
#endif
#define MAX_CONN_TIMES 10/* return  typeREDIS_REPLY_STRING  : 1REDIS_REPLY_ARRAY : 2REDIS_REPLY_INTEGER :3REDIS_REPLY_NIL  : 4REDIS_REPLY_STATUS : 5REDIS_REPLY_ERROR : 6
*/
bool RedisClient::isConnOk()
{if (conn == nullptr)return false;if (checkError() > 0)return false;if ( !(conn->flags & REDIS_CONNECTED) ){return false;}bool ret = false;redisReply *reply = static_cast<redisReply*>(redisCommand(conn, "PING"));if (reply == nullptr)return false;if (reply->len > 0)ret = true;freeReplyObject(reply);return ret;
}bool RedisClient::Reconnect()
{this->Close();int n = 0;bool ret = Conn(_ip.c_str(), _port);while (ret == false && n < MAX_CONN_TIMES){ret = Conn(_ip.c_str(), _port);n++;}return ret;
}bool RedisClient::Conn(const char * ip, int port)
{this->_ip = ip;this->_port = port;if (conn != nullptr)return 0;conn = redisConnect(ip, port);//struct timeval tm;//tm.tv_sec = 2;//tm.tv_sec = 0;//conn = redisConnectWithTimeout(ip, port, tm);if (conn->err){printf("redis connection error:%s\n", conn->errstr);return false;}return true;
}size_t RedisClient::SetHValue(std::string & table, std::string & field, const char * value, size_t len)
{redisReply* reply = static_cast<redisReply*>(redisCommand(conn, "HSET  %b %b %b", table.c_str(), table.size(),field.c_str(),field.size(),value, len));if (reply == nullptr)return 0;size_t ret = 0;if (reply->type == REDIS_REPLY_INTEGER){ret = reply->integer;}freeReplyObject(reply);return ret;}size_t RedisClient::SetHValue(std::string & table, std::string & field, std::string & value)
{if (conn == nullptr)return -1;std::string cmd;std::stringstream stream;stream << "HSET " << table << " "<< field << " " << value;cmd = stream.str();redisReply* reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (reply == nullptr)return 0;size_t ret = 0;if (reply->type == REDIS_REPLY_INTEGER){ret = reply->integer;}freeReplyObject(reply);return ret;
}int64_t RedisClient::INCR(const char * table, const char * field, int count)
{if (conn == nullptr)return -1;std::string cmd = "";std::stringstream stream;stream << "hincrby " << table << " " << field << " " << count;cmd = stream.str();redisReply* reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (reply == nullptr)return 0;int64_t ret = reply->integer;freeReplyObject(reply);return ret;
}int64_t RedisClient::INCR(std::string & table, std::string & field, int count)
{return INCR(table.c_str(), field.c_str(), count);
}
size_t RedisClient::QueryKeys(std::string & table, std::map<uint32_t, string>& map)
{std::string cmd = "";std::stringstream stream;stream << " HKEYS " << table;cmd = stream.str();redisReply *reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));size_t len = 0;if (reply == nullptr)return 0;for (size_t i = 0; i < reply->elements; i++){redisReply * item = *(reply->element + i);uint32_t id = atoi(item->str);map.insert(std::pair<uint32_t, string>(id, item->str));if (id > len)len = id;}freeReplyObject(reply);return len;}size_t RedisClient::QueryKeys(std::string & table, std::vector<std::string>& vec)
{std::string cmd = "";std::stringstream stream;stream << " HKEYS " << table;cmd = stream.str();redisReply *reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (reply == nullptr)return 0;size_t len = reply->elements;for (size_t i = 0; i < reply->elements; i++){redisReply * item = *(reply->element + i);vec.push_back(item->str);//item->str;}freeReplyObject(reply);return len;
}size_t RedisClient::QueryCount(const char * table)
{std::string cmd = "";std::stringstream stream;stream << " HLEN " << table;cmd = stream.str();redisReply *reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (reply == nullptr)return 0;//_atoi64(char *)//char *end;//strtoll(reply->str, &end, 10);size_t len = reply->integer;freeReplyObject(reply);return len;
}
size_t RedisClient::QueryCount(string & table)
{return QueryCount(table.c_str());
}size_t RedisClient::Query(std::string & table, std::string & field, std::string & value)
{std::string cmd = "";std::stringstream stream;stream << " HGET " << table << " " << field;cmd = stream.str();redisReply *reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (reply == nullptr)return 0;size_t len = reply->len;value = reply->str;freeReplyObject(reply);return len;
}
size_t RedisClient::Query(std::string & table, std::string & field, CharVector & value)
{std::string cmd = "";std::stringstream stream;stream << " HGET " << table << " " << field;cmd = stream.str();redisReply *reply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (reply == nullptr)return 0;size_t len = reply->len;value.reserve(len);value.append(reply->str, len);freeReplyObject(reply);return len;
}size_t RedisClient::Query(const char * table, const char * field, char ** pValue)
{std::string cmd = "";std::stringstream stream;stream << " HGET " << table << " " << field;cmd = stream.str();if (getReply)freeReplyObject(getReply);getReply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));if (getReply == nullptr)return 0;*pValue = getReply->str;size_t len = getReply->len;return len;
}void RedisClient::Close()
{if (getReply != nullptr){freeReplyObject(getReply);getReply = nullptr;}if (conn != nullptr){redisFree(conn);conn = nullptr;}
}int RedisClient::checkError()
{if (conn->err == REDIS_ERR_IO || conn->err == REDIS_ERR_EOF){return 1;}return 0;
}

之后随便封装一个管理的接口:

myRedis.h

#pragma once
#include <stdint.h>//#define DLLIMPORT extern "C" __declspec(dllimport)
#define DLLIMPORT extern "C" DLLIMPORT void      myRedisPut(uint64_t idx);
DLLIMPORT uint64_t  myRedisGet(const char *ip, int port);
DLLIMPORT size_t    myRedisClear();DLLIMPORT size_t hashSetBytes(uint64_t idx, const char * table, const char * field, const char * value, size_t len);
DLLIMPORT size_t hashGetBytes(uint64_t idx, const char * table, const char * field, char ** pValue);
DLLIMPORT size_t hashQueryLen(uint64_t idx, const char * table);
DLLIMPORT int64_t hashIncBy(uint64_t idx, const char * table, const char * field, int count);

在dll中定义如下:myRedis.cpp

#include "../testRedis/RedisClient.h"
#include <mutex>
#include <deque>#define DLLEXPORT extern "C" __declspec(dllexport) using namespace robin;
using RedisClient_Ptr = shared_ptr<RedisClient>;
static std::mutex poolMutex;static std::map<uint64_t, RedisClient_Ptr>  usedMap;
static std::deque<RedisClient_Ptr> idleQue;// find out an unused id
// if 0, then close and free
uint64_t findId()
{for (uint64_t i = 1; i < 1000; i++){auto it = usedMap.find(i);if (it == usedMap.end()){return i;}}return 0;
}// read write to get pointer
RedisClient_Ptr findClient(uint64_t idx)
{std::lock_guard < std::mutex > guard(poolMutex);auto it = usedMap.find(idx);if (it == usedMap.end())return nullptr;return usedMap[idx];
}///
DLLEXPORT size_t myRedisClear()
{std::lock_guard < std::mutex > guard(poolMutex);size_t n = idleQue.size();printf("idleQueSize =%zu , using=%zu \n", idleQue.size(), usedMap.size());idleQue.clear();usedMap.clear();return n;
}DLLEXPORT void myRedisPut(uint64_t idx)
{std::lock_guard < std::mutex > guard(poolMutex);auto it = usedMap.find(idx);if (it == usedMap.end())return;RedisClient_Ptr client = usedMap[idx];idleQue.push_back(client);usedMap.erase(idx);//printf("put back %ju, using=%ju, idle=%ju \n", idx, usedMap.size(), idleQue.size());}// return id
DLLEXPORT uint64_t  myRedisGet(const char *ip, int port)
{RedisClient_Ptr client;uint64_t idx;// mutex{std::lock_guard < std::mutex > guard(poolMutex);idx = findId();if (idx == 0)return idx;if (idleQue.size() > 0){client = idleQue[0];idleQue.pop_front();usedMap.insert(std::make_pair(idx, client));}else{client = make_shared<RedisClient>();usedMap.insert(std::make_pair(idx, client));}}bool ret = client->isConnOk();if (ret == false){client->Close();ret = client->Conn(ip, port);}if (ret == false){myRedisPut(idx);return 0;}return idx;
}//
DLLEXPORT int hashSetBytes(uint64_t idx,  const char * table, const char * field, const char * value, size_t len)
{RedisClient_Ptr  client = findClient(idx);if (!client)return -1;std::string table1(table);std::string field1(field);return client->SetHValue(table1, field1, value, len);
}DLLEXPORT size_t hashGetBytes(uint64_t idx, const char * table, const char * field, char ** pValue)
{RedisClient_Ptr  client = findClient(idx);if (!client)return -1;return client->Query(table, field, pValue);
}DLLEXPORT size_t hashQueryLen(uint64_t idx, const char * table)
{RedisClient_Ptr  client = findClient(idx);if (!client)return -1;return client->QueryCount(table);
}DLLEXPORT int64_t hashIncBy(uint64_t idx, const char * table, const char * field, int count)
{RedisClient_Ptr  client = findClient(idx);if (!client)return -1;std::string table1(table);std::string field1(field);return client->INCR(table1, field1, count);
}

注意:在dllmain中需要记得清理资源:

#include "pch.h"
#include "../testMyRedis/myRedis.h"BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;case DLL_PROCESS_DETACH:myRedisClear();break;}return TRUE;
}

编译好了dll文件,就可以简单的测试一下了:

// testMyRedis.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <stdint.h>
#include <sstream>
#include <thread>#include "myRedis.h"
#pragma comment(lib, "RedisDll.lib")
using namespace std;void testFunc(int id)
{stringstream table;table << "x-node";table << id;for (int n = 0; n < 1000; n++){uint64_t idx = myRedisGet("127.0.0.1", 6379);if (idx == 0){std::cout << "error : get id = 0\n";return;}//std::cout << "get id = " << idx << endl;stringstream field;field << "num" << n;stringstream str;str << n;size_t ret = hashSetBytes(idx, table.str().c_str(), field.str().c_str(),str.str().c_str(), str.str().size());//cout << ret << endl;// get testchar * buf = nullptr;ret = hashGetBytes(idx, table.str().c_str(), field.str().c_str(), &buf);if (ret < 1){}else{//string str(buf, ret);//std::cout << "get str = " << str.c_str() << endl;}// incret = hashIncBy(idx, table.str().c_str(), "count", 1);myRedisPut(idx);}// test count == 100000uint64_t idx = myRedisGet("127.0.0.1", 6379);char * buf = nullptr;size_t ret = hashGetBytes(idx, table.str().c_str(), "count", &buf);if (ret < 1){std::cout << table.str().c_str() << " count=error" << endl;}else{string str(buf, ret);std::cout << table.str().c_str() <<" count= " << str.c_str() << endl;}ret = hashQueryLen(idx, table.str().c_str());std::cout << table.str().c_str() << " elements= " << ret << endl;}int main()
{std::thread thread1 = thread(testFunc, 1);std::thread thread2 = thread(testFunc, 2);std::thread thread3 = thread(testFunc, 3);std::thread thread4 = thread(testFunc, 4);thread1.join();thread2.join();thread3.join();thread4.join();char c;//cin >> c;return 1;
}

各个写入动作虽然没有测试,但是结果好像还凑合:

x-node4 count= 1000
x-node4 elements= 1001
x-node2 count= 1000
x-node2 elements= 1001
x-node1 count= 1000
x-node1 elements= 1001
x-node3 count= 1000
x-node3 elements= 1001
idleQueSize =0 , using=4
~RedisClient()
~RedisClient()
~RedisClient()
~RedisClient()

vc使用hiredis的几个填坑动作相关推荐

  1. 用MinGW编译AWTK填坑录

    AWTK 全称为 Toolkit AnyWhere,是 ZLG 倾心打造的一套基于 C 语言开发的 GUI 框架.旨在为用户提供一个功能强大.高效可靠.简单易用.可轻松做出炫酷效果的 GUI 引擎,并 ...

  2. java.lang.OutOfMemoryError:GC overhead limit exceeded填坑心得

    该文章出自:http://www.cnblogs.com/hucn/p/3572384.html 分析工具:http://www.blogjava.net/jjshcc/archive/2014/03 ...

  3. 20150726 填坑日记

    三中内填坑: 1. 组合数递推什么的 C(m,n)=C(m,n-1)+C(m-1,n-1).填了个大坑,以前没认真听课QAQ 2. 裸题过河卒 3. 缺角正方形摆放车统计,分上下部分,枚举上部分放几个 ...

  4. 传统行业转型微服务的挖坑与填坑

    原文:传统行业转型微服务的挖坑与填坑 一.微服务落地是一个复杂问题,牵扯到IT架构,应用架构,组织架构多个方面 在多家传统行业的企业走访和落地了微服务之后,发现落地微服务是一个非常复杂的问题,甚至都不 ...

  5. 开发工具总结(4)之Android Studio3.0填坑指南

    序言 Android Studio 3.0 上篇讲了: 全面总结Android Studio2.X的填坑指南 这篇讲一下AS3.0的坑.. 作为这个世界上走在最前沿的生物"猿",怎 ...

  6. 【结果很简单,过程很艰辛】记阿里云Ons消息队列服务.NET接口填坑过程

    Maybe 这个问题很简单,因为解决方法是非常简单,但填坑过程会把人逼疯,在阿里云ONS工作人员.同事和朋友的协助下,经过一天的调试和瞎捣鼓,终于解决了这个坑,把问题记下来,也许更多人在碰到类似问题的 ...

  7. Android Studio 填坑指南

    前几天发布了一篇名为<Android Studio 安装.配置及第一个程序演示>的博文,有不少童鞋都认真阅读过并照步骤一步一步操作了一遍,有滴如期成功地装好了,然鹅有滴反映说这不对呀,为森 ...

  8. 即将上线的Hive服务器面临的一系列填坑笔记

    即将上线的Spark服务器面临的一系列填坑笔记 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.18/10/19 16:36:31 WARN metastore.ObjectSt ...

  9. 第二篇:salt-api使用填坑指南

    前言 salt-api在使用时,有些坑欲哭无泪,一路趟雷过后,总结了一趟salt-pai使用填坑指南,保君一路畅通. salt-api 安装 #本文的安装版本 2018.3.2-1.el6 yum i ...

最新文章

  1. 《OpenCV3编程入门》学习笔记8 图像轮廓与图像分割修复(三)使用多边形将轮廓包围
  2. ICLR 2022 under review|化学反应感知的分子表征学习
  3. Temporary failure in name resolution
  4. CodeForces 721C Journey
  5. Hello,SDK!数据采集黑客松大赛重磅开启,Mac投影仪任你拿!
  6. 介绍一个非常实用的Visual Studio Code扩展 - indent-rainbow
  7. 前端学习(3241):react生命周期forceUpdate
  8. 华为路由器上有没有mac表_MAC地址表、ARP缓存表、路由表及交换机、路由器基本原理...
  9. Python_迭代器Iterator
  10. 用oracle的java存储过程实现BLOB字段的字符串读取
  11. 六界仙尊h5服务器维护多久,《六界仙尊》5月6日更新维护 公开虚天BOSS坐标
  12. 好用到爆!轻松获取PNG透明图片!
  13. oracle 导入数据时主键丢失,Oracle 插入数据 返回主键
  14. c# 操作 Excel
  15. android 三方_面试官送你一份Android热门三方库源码面试宝典及学习笔记
  16. ArcGIS土壤稳定性评估(附练习数据下载)
  17. 服务器网卡支持25G,25G服务器网卡光模块解决方案
  18. wps 的直接登录URL
  19. 求连通块的数量(dfs、bfs)
  20. 【Codeforces 1157F】 Maximum Balanced Circle | 思维、dp、二分

热门文章

  1. 【Excel自动化办公Part6】:插入图片、插入柱状图、插入条形图
  2. VScode怎么开启本地服务器及本地调试?
  3. 尚学堂Java第八章编码题
  4. Mac Sublime Text 3中文汉化
  5. Windows10 下安装 dig 命令的步骤(一)
  6. xubuntu20.04+virtualbox6+direct3d安装吃屎记
  7. Unity:使用Catmull-Rom曲线创建道路模型
  8. 虹科 | 主机总线适配器:CPU的“速效救心丸”
  9. 【STC单片机学习】第十四课:SPI通信-实时时钟DS1302
  10. html5 2019新年祝福页面,2019最新创意暖心新年祝福语 简单的祝福 - 中国万年历