redis async client 与自有框架集成
hiredis的异步接口已经支持ae libuv libev 和 libevent集成,具体头文件可以参见redis/deps/hiredis/adapters,样例参见redis/deps/hiredis/examples.
完整样例参见: https://github.com/DavadDi/study_example/tree/master/async_redis_client
参照hireids的异步接口和libevent的集成可以很容易和其他网络框架集成,例如asio或者ace等。 以下样例为自己编写reactor框架的集成方式,
支持自动重练和asyncRedisContext对象的创建和释放,重练使用退步算法,最大连接时间间隔为32秒。
使用方式:
将redis_client.hpp 放到 hiredis的adapter目录即可。
#ifndef redis_client_h
#define redis_client_h #include "reactor/define.hpp"
#include "reactor/event_handler.hpp"
#include "hiredis.h"
#include "async.h" using namespace reactor; static void redisReactorAddRead(void *arg);
static void redisReactorDelRead(void *arg);
static void redisReactorAddWrite(void *arg);
static void redisReactorDelWrite(void *arg);
static void redisReactorCleanup(void *arg); void connectCallBack(const redisAsyncContext *c, int status);
void disconnectCallBack(const redisAsyncContext *c, int status); void get_call_fun(redisAsyncContext *c, void *r, void *arg)
{
redisReply *reply = (redisReply *)r;
std::string *key_str = (std::string *)arg; if (reply == NULL)
{
delete key_str;
return;
} LOG_INFO("[%s] -> %s\n", key_str->c_str(), reply->str); delete key_str; /* Disconnect after receiving the reply to GET */
// redisAsyncDisconnect(c);
} // -------------------------------------------------------------------
// !!NOTE, if obj conneted to server faild and unregister from epoll,
// prog exit, this object my leak memory
// ------------------------------------------------------------------- class CRedisClient : public CEventHandler
{
public:
// enum {MAX_BUF_SIZE = 4096};
typedef CEventHandler super; CRedisClient(const char *srv_ip, uint16_t srv_port, reactor::CReactor *reactor)
: super(reactor)
{
m_srv_ip_str = srv_ip;
m_srv_port = srv_port;
} int connect()
{
LOG_DEBUG("Enter CRedisClient connect()");
m_client_status = CONNECT_STATUS::CLIENT_CONNECTING; clear_redis_context(); m_redis_context = redisAsyncConnect(m_srv_ip_str.c_str(), m_srv_port);
if (m_redis_context == nullptr)
{
return -;
} if (m_redis_context->err)
{
LOG_INFO("Connect to %s:%d Error: %s",
m_srv_ip_str.c_str(), m_srv_port, m_redis_context->errstr); return -;
} if (m_timer_id == )
{
m_timer_id = this->reactor()->regist_timer(this, m_timeout_value); // only one time
LOG_DEBUG("Client regist timer to reactor id %d, timeout %d", m_timer_id, m_timeout_value);
} this->attach(); return ;
} virtual ~CRedisClient()
{
// maybe should not free redis context in deconstuct!!
m_delete_redis_context = true;
clear_redis_context();
} virtual int open(void *data = nullptr)
{
m_client_status = CONNECT_STATUS::CLIENT_CONNECTED; m_delete_redis_context = false; if (m_timer_id == )
{
m_timer_id = this->reactor()->regist_timer(this, m_timeout_value); // only one time
LOG_DEBUG("Client regist timer to reactor id %d, timeout %d",
m_timer_id, m_timeout_value);
} LOG_INFO("Connect to RedisServer %s:%d succeed!!",
m_srv_ip_str.c_str(), m_srv_port); return ;
} virtual int handle_input(socket_t socket)
{
redisAsyncHandleRead(m_redis_context);
return ;
} virtual int handle_output(socket_t socket)
{
redisAsyncHandleWrite(m_redis_context);
return ;
} virtual int handle_timeout(uint32_t tm, void *data = nullptr)
{
// LOG_DEBUG("Enter into timeout function....");
if (m_client_status == CONNECT_STATUS::CLIENT_CONNECTED)
{
/* just for test */
std::string key = std::to_string(tm); LOG_DEBUG("Set key %s", key.c_str());
redisAsyncCommand(m_redis_context, NULL, NULL, "SET %s %s",key.c_str(), "aaa");
redisAsyncCommand(m_redis_context, get_call_fun, (char*)new string(key), "GET %s", key.c_str());
}
else
{
static uint32_t last_tm = ;
if ((tm - last_tm) >= m_timeout_interval)
{
//reconnect
LOG_DEBUG("Start reconnect now ...");
this->connect(); m_timeout_interval = m_timeout_interval * ;
if (m_timeout_interval > )
{
m_timeout_interval = ;
} last_tm = tm;
}
} return ;
} virtual int handle_close(socket_t socket = INVALID_SOCKET, uint32_t mask = )
{
LOG_DEBUG("Enter into handle_close()");
m_client_status = CONNECT_STATUS::CLIENT_UNCONNECTED; // epoll call delete this handler
if (mask & RE_MASK_DEL)
{
LOG_DEBUG("Call RE_MASK_DEL now"); if (this->m_timer_id && (this->reactor() != nullptr))
{
this->reactor()->unregist_timer(this->m_timer_id);
this->m_timer_id = ;
} delete this;
return ;
} this->reactor()->del_event(this,);
return ;
} void clear_redis_context()
{
if (m_delete_redis_context && m_redis_context != nullptr)
{
LOG_DEBUG("Call redisAsynFree() now");
redisAsyncFree(m_redis_context);
m_redis_context = nullptr;
}
} int attach()
{
LOG_DEBUG("Enter attatch function... "); redisContext *context = &(m_redis_context->c);
if (m_redis_context->ev.data != NULL)
{
return -;
} // set callback function
redisAsyncSetConnectCallback(m_redis_context,connectCallBack);
redisAsyncSetDisconnectCallback(m_redis_context,disconnectCallBack); this->set_handle(context->fd); // set handler m_redis_context->ev.addRead = redisReactorAddRead;
m_redis_context->ev.delRead = redisReactorDelRead;
m_redis_context->ev.addWrite = redisReactorAddWrite;
m_redis_context->ev.delWrite = redisReactorDelWrite;
m_redis_context->ev.cleanup = redisReactorCleanup;
m_redis_context->ev.data = this; LOG_DEBUG("ac->ev.data %p", m_redis_context->ev.data); this->add_read();
this->add_write(); return ;
} void add_read()
{
LOG_TRACE_METHOD(__func__); if( (this->m_current_event_mask & reactor::EVENT_READ) > )
{
LOG_DEBUG("EV_READ(0x%0x) already in event_mask 0x%x",
reactor::EVENT_READ, this->m_current_event_mask); return;
} this->reactor()->add_event(this, reactor::EVENT_READ);
} void del_read()
{
LOG_TRACE_METHOD(__func__);
this->reactor()->mod_event(this, this->m_current_event_mask&(~reactor::EVENT_READ));
} void add_write()
{
LOG_TRACE_METHOD(__func__);
this->schedule_write();
} void del_write()
{
LOG_TRACE_METHOD(__func__);
this->cancel_schedule_write();
} void clean_up()
{
LOG_TRACE_METHOD(__func__);
} // note!!!
// connenct not succeed. we can free redis context. ]
// But if connect succeed and borken, we don't connect protected:
std::string m_srv_ip_str;
uint16_t m_srv_port; CONNECT_STATUS m_client_status = CONNECT_STATUS::CLIENT_UNCONNECTED; int m_timer_id = ;
uint32_t m_timeout_value = ;
uint32_t m_timeout_interval = ; bool m_delete_redis_context = true;
redisAsyncContext *m_redis_context = nullptr;
}; static void redisReactorAddRead(void *arg)
{
LOG_DEBUG("Enter redisReactorAddRead() arg %p", arg);
CRedisClient *event_handler = (CRedisClient *)arg;
event_handler->add_read();
} static void redisReactorDelRead(void *arg)
{
CRedisClient *event_handler = (CRedisClient *)arg;
event_handler->del_read();
} static void redisReactorAddWrite(void *arg)
{
CRedisClient *event_handler = (CRedisClient *)arg;
event_handler->add_write();
} static void redisReactorDelWrite(void *arg)
{
CRedisClient *event_handler = (CRedisClient *)arg;
event_handler->del_write();
} static void redisReactorCleanup(void *arg)
{
CRedisClient *event_handler = (CRedisClient *)arg;
event_handler->clean_up();
} void connectCallBack(const redisAsyncContext *ac, int status)
{
if (status != REDIS_OK)
{
LOG_ERROR("connectCallBack() Error: %s", ac->errstr);
return;
} CRedisClient *event_handler = (CRedisClient *)ac->ev.data;
event_handler->open(); LOG_INFO("RedisClient Connected...");
} void disconnectCallBack(const redisAsyncContext *ac, int status)
{
CRedisClient *event_handler = (CRedisClient *)ac->ev.data;
event_handler->handle_close(,); if (status != REDIS_OK)
{
LOG_INFO("disconnectCallBack()!! Error: %s", ac->errstr);
return;
} LOG_INFO("RedisClient Disconnected...");
} #endif /* redis_client_h */
使用的程序样例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h> //#include <hiredis.h>
//#include <async.h> #include <adapters/redis_client.hpp>
//#include "redis_client.hpp" #include <signal.h> static void signal_handler(int sig)
{
if (sig == SIGINT)
{
reactor::CReactor::instance()->end_event_loop();
}
} /*
void get_call_fun(redisAsyncContext *c, void *r, void *arg)
{
redisReply *reply = (redisReply *)r;
std::string *key_str = (std::string *)arg; if (reply == NULL)
{
delete key_str;
return;
} LOG_INFO("[%s] -> %s\n", key_str->c_str(), reply->str); delete key_str; // Disconnect after receiving the reply to GET
// redisAsyncDisconnect(c);
}
*/ int main (int argc, char **argv)
{
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, signal_handler); CLoggerMgr logger("reactor.prop"); reactor::CReactor *rt = reactor::CReactor::instance();
CRedisClient *redis_client = new CRedisClient("127.0.0.1", , rt);
redis_client->connect(); rt->run_event_loop(); return ;
}
redis async client 与自有框架集成的更多相关文章
- Redis java client ==> Jedis
https://github.com/xetorthio/jedis Jedis is a blazingly small and sane Redis java client. Jedis was ...
- Spring集成Redis集群(含spring集成redis代码)
代码地址如下:http://www.demodashi.com/demo/11458.html 一.准备工作 安装 Redis 集群 安装参考: http://blog.csdn.net/zk6738 ...
- Spring cloud 基础框架集成
Spring cloud 基础框架集成 1. 注册中心 -eurekar 1. pom依赖 <?xml version="1.0" encoding="UTF-8& ...
- Spring+SpringMvc+Mybatis框架集成搭建教程
一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...
- Spring与其他Web框架集成
Spring与多种流行Web应用框架(Struts.JSF和DWR)集成的方法. Spring强大的IoC容器和企业支持特性使其十分适于实现Java EE应用的服务和持续层. 对于表现层,可以在许多不 ...
- Cordova与现有框架的结合,Cordova插件使用教程,Cordova自定义插件,框架集成Cordova,将Cordova集成到现有框架中
一.框架集成cordova 将cordova集成到现有框架中 一般cordova工程是通过CMD命令来创建一个工程并添加Android.ios等平台,这样的创建方式可以完整的下载开发过程中所需要的的插 ...
- Spring MVC 学习总结(十一)——IDEA+Maven+多模块实现SSM框架集成
一.SSM概要 与SSH(Struts/Spring/Hibernate/)一样,Spring+SpringMVC+MyBatis也有一个简称SSM,Spring实现业务对象管理,Spring MVC ...
- Selenium·自动化框架集成
date:2018513 day08aft 一.自动化框架集成分层 1.config 配置(项目配置——测试环境,公司环境,线上环境:以中国人才热线登陆为例,网址.用户名.密码等) 2.public ...
- Spring MVC 学习总结(十)——Spring+Spring MVC+MyBatis框架集成(IntelliJ IDEA SSM集成)
与SSH(Struts/Spring/Hibernate/)一样,Spring+SpringMVC+MyBatis也有一个简称SSM,Spring实现业务对象管理,Spring MVC负责请求的转发和 ...
随机推荐
- Winpcap
Winpcap网络开发库入门
- jquery实践案例--验证电子邮箱
<input type="email" name="email" id="email" value="" onpa ...
- fork函数
在Unix/Linux中用fork函数创建一个新的进程.进程是由当前已有进程调用fork函数创建,分叉的进程叫子进程,创建者叫父进程.该函数的特点是调用一次,返回两次,一次是在父进程,一次是在子进程. ...
- PHP后门隐藏与维持技巧
在一个成功的测试后,通常会想让特权保持的更久些.留后门的工作就显得至关重要,通常布设的后门包括但不限于数据库权限,WEB权限,系统用户权限等等.此文则对大众后门隐藏的一些思路做科普. AD: 0×00 ...
- 调用手机话费充值API的SDK编写思路
思路 通过将SDK方法中返回的数据划分为正常返回数据以及错误返回的数据两部分,让调用者更简单的对接口调用错误进行处理. 将SDK调用第三方服务接口的流程划分为: 数据准备,http请求,结果处理三部分 ...
- 【读书笔记《Android游戏编程之从零开始》】11.游戏开发基础(SurfaceView 游戏框架、View 和 SurfaceView 的区别)
1. SurfaceView 游戏框架实例 实例效果:就是屏幕上的文本跟着点击的地方移动,效果图如下: 步骤: 新建项目“GameSurfaceView”,首先自定义一个类"MySurfac ...
- 关于CSS中的字体尺寸设置 em rem等
常用单位 在CSS中可以用很多不同的方式来设定字体的尺寸.一般来说,这些单位被分成两大类:绝对单位(absolute)和相对单位(relative). 绝对单位在大多数情况下是相对于某些实际量度而言的 ...
- jquery中的clone()方法使用
clone([Even[,deepEven]]) 描述: 克隆匹配的DOM元素并且选中这些克隆的副本. 在想把DOM文档中元素的副本添加到其他位置时这个函数非常有用. 1:一个布尔值(true 或者 ...
- 纯js和纯css+html制作的手风琴的效果
一:纯css+html的手风琴效果 这种用css写的手风琴比较简单,主要是应用到css中的,transition属性. 代码如下: <!DOCTYPE HTML> <html> ...
- SQL Server 2005 安装图解教程(Windows)
因工作需要,好久未安装SQL Server2005,今天安装了一下,特此写下安装步骤留下笔记. 安装前准备: 先安装IIS,再安装SQL Server2005 一.安装 点击安装,如下图: 选择操作系 ...