采用Redis统计客户端在线用户——客户端(windows)篇

3 篇文章 0 订阅
2 篇文章 0 订阅
  • 描述:为了知道在线用户数,计算客户端奔溃率(方便我们知道当前客户端的稳定性),在客户端加入统计功能模块。
  • 声明:本人是第一次接触Redis,若有错误之处,还望各位大佬指教!

安装Redis以及编译hiredis.lib

  • 安装Redis很简单的,去这下载之后可安装:点击这里
  • 编译hiredis.lib:由于项目编译环境比较老,是VS2010,可在这里下载进行编译:Redis2.6,提取密码: wahn
  • 个人心得:如果低版本的vs不要去折腾高版本的Redis,折腾不出什么结果;

思想(初学小白,多多指点)

  • 在客户端加入统计功能,会使用到set和hash。
  • 当天的用户创建以“2018-04-04”为例的key值,value是用户id。利用集合set的命令”sadd 2018-04-04 userid”,该key的生命周期设置为86400s。那么问什么会用到set呢,一天之后还要让它消逝?就是为了辅助判断,当前用户是否为当天第一次登录,不重复统计。因为一天之后,数据统计完整,这个key无需存在。
  • 然后就是根据set辅助判断的返回值的真假再采用hash的命令hincrby key filed value该格式进行统计。我在这采用的方法是 以“2018-04”为例的key值,“04”为例的filed值,value呢 ?肯定就是1(因为当判断登录用户时第一次登录 就加一)。为什么要这样设计,因为前段展示曲线图的时候是按月为最小单位展示的,这样设计,只对redis访问一次就可以拿到数据。(ps:估计还有所欠缺,暂时没考虑到)
    RedisServerDB.h代码:
#pragma once
#include <stdio.h>
#include <iostream>
#include "hiredis.h"  
#define NO_QFORKIMPL //这一行必须加才能正常使用
#include <string>  
#include <vector>

#define strcasecmp _stricmp  

using namespace std;

#pragma comment(linker,"/NODEFAULTLIB:LIBCMT.lib")  
#pragma comment (lib,"hiredis.lib")  
/*添加socket链接库*/
#pragma comment(lib,"Ws2_32.lib")  

//函数声明  
redisContext* OnConnectRedisServer();
bool OnSetRedisAccountValue(string strKeyCurrDate, string strValueAccount);
bool OnCheckKey2ValueIsExist(string strKeyCurrDate, string strValueAccount);
bool OnCheckKeyIsExist(string strKeyCurrDate);
bool OnHincrbyRedisKeyValue(string strKeyCurrDate,string strValueAccount, string strHincrbyUserKeyDate,string strHincrbyUserKeyDay);
bool setKeyCurrDateExpire(string strKeyCurrDate, int expire, redisContext* context);
bool OnHincrbyAccountLength(string strCurrKeyMonth, string strKeyCurrDate);
CString StrongString2Cstring(string strData);


RedisServerDB.cpp代码:

#include "stdafx.h"
#include "RedisServerDB.h"

#define KEYEXPIRELEKEACCOUNT  86400  //一天

redisContext* OnConnectRedisServer()
{
    //redis默认监听端口为6379 可以再配置文件中修改  
    redisContext* rConnect = redisConnect("127.0.0.1", 6379);
    if (rConnect->err)
    {
        redisFree(rConnect);
        XLogError(L"连接Redis服务器失败");
        //exit(0);
        return NULL;
    }
    XLogInfo(L"连接Redis服务器成功");
    return rConnect;
}

//写入数据
bool OnSetRedisAccountValue(string strKeyCurrDate, string strValueAccount)
{
    CString cstrKeyCurrDate, cstrValueAccount;
    cstrKeyCurrDate = StrongString2Cstring(strKeyCurrDate);
    cstrValueAccount = StrongString2Cstring(strValueAccount);
    redisContext* rConnectRServer = OnConnectRedisServer();
    if (rConnectRServer == NULL)
    {
        return false;
    }
    string command = "sadd " + strKeyCurrDate + " " + strValueAccount;
    redisReply* rReply = (redisReply*)redisCommand(rConnectRServer, command.c_str());
    CString cstrCommand = StrongString2Cstring(command);
    if (NULL == rReply)
    {
        XLogError(L"在[%s]写入数据[%s]失败(Command返回的应答对象指针为空){ Command:%s }", cstrKeyCurrDate, cstrValueAccount, cstrCommand);
        redisFree(rConnectRServer);
        return false;
    }
    if (!(rReply->type == REDIS_REPLY_INTEGER && rReply->integer == 1))
    {
        XLogError(L"在[%s]写入数据[%s]失败{ Command:%s }", cstrKeyCurrDate, cstrValueAccount, cstrCommand);
        freeReplyObject(rReply);
        redisFree(rConnectRServer);
        return false;
    }
    freeReplyObject(rReply);
    redisFree(rConnectRServer);
    XLogInfo(L"在[%s]写入数据[%s]成功{ Command:%s }", cstrKeyCurrDate, cstrValueAccount, cstrCommand);
    return true;
}
//检查key是否存在于redis-server
bool OnCheckKeyIsExist(string strKeyCurrDate)
{
    CString cstrKeyCurrDate;
    cstrKeyCurrDate = StrongString2Cstring(strKeyCurrDate);
    redisContext* rConnectRServer = OnConnectRedisServer();
    if (rConnectRServer == NULL)
    {
        return false;
        XLogError(L"OnCheckKeyIsExist()链接redis-server failed");
    }
    string cmdkeyisexist = "exists " + strKeyCurrDate;
    redisReply* rReply = (redisReply*)redisCommand(rConnectRServer, cmdkeyisexist.c_str());
    CString cstrCmdkeyisexist = StrongString2Cstring(cmdkeyisexist);
    if (rReply == NULL)
    {
        XLogError(L"函数OnCheckKeyIsExist(),Command返回应答对象指针为空{Command:%s}", cstrCmdkeyisexist);
        redisFree(rConnectRServer);
        return false;
    }
    if (rReply->integer == 1)
    {
        freeReplyObject(rReply);
        redisFree(rConnectRServer);
        XLogInfo(L"[%s]存在 { Command:%s }", cstrKeyCurrDate, cstrCmdkeyisexist);
        return true;
    }
    freeReplyObject(rReply);
    redisFree(rConnectRServer);
    XLogInfo(L"[%s]不存在 { Command:%s }", cstrKeyCurrDate, cstrCmdkeyisexist);
    return false;
}

//检查当前key对应value是否存在(辅助判断当天是否登录过)
bool OnCheckKey2ValueIsExist(string strKeyCurrDate, string strValueAccount)
{
    CString cstrKeyCurrDate, cstrValueAccount;
    cstrKeyCurrDate = StrongString2Cstring(strKeyCurrDate);
    cstrValueAccount = StrongString2Cstring(strValueAccount);
    cstrValueAccount = StrongString2Cstring(strValueAccount);
    redisContext* rConnectRServer = OnConnectRedisServer();
    if (rConnectRServer == NULL)
    {
        return false;
    }
    string command = "sismember " + strKeyCurrDate + " " + strValueAccount;
    redisReply* rReply = (redisReply*)redisCommand(rConnectRServer, command.c_str());
    CString cstrCommand = StrongString2Cstring(command);
    //查找不成功的情况:
    if (rReply == NULL)
    {
        XLogError(L"Redis查询[%s]存在于集合[%s]中?Command返回应答对象指针为空{Command:%s}",cstrValueAccount, cstrKeyCurrDate, cstrCommand);
        redisFree(rConnectRServer);
        return false;
    }
    if (rReply->integer==1)
    {
        freeReplyObject(rReply);
        redisFree(rConnectRServer);
        XLogInfo(L"[%s]存在于集合[%s]中{ Command:%s }", cstrValueAccount, cstrKeyCurrDate, cstrCommand);
        return true;
    }
    freeReplyObject(rReply);
    redisFree(rConnectRServer);
    XLogInfo(L"[%s]不存在于集合[%s]中{ Command:%s }", cstrValueAccount, cstrKeyCurrDate, cstrCommand);
    return false;
}

bool OnHincrbyRedisKeyValue(string strKeyCurrDate, string strValueAccount ,string strHincrbyUserKeyDate, string strHincrbyUserKeyDay)
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 1), &wsaData);
    redisContext* rConnectRServer = OnConnectRedisServer();
    if (rConnectRServer == NULL)
    {
        return false;
    }
    if (!OnCheckKeyIsExist(strKeyCurrDate))
    {
        //设置周期
        if (!SetKeyCurrDateExpire(strKeyCurrDate, KEYEXPIRELEKEACCOUNT, rConnectRServer))
        {
            redisFree(rConnectRServer);
            return false;
        }
    }
    bool bCheckValueIsExist = OnCheckKey2ValueIsExist(strKeyCurrDate, strValueAccount);
    //若存在则不对redis进行set(sadd)
    if (!bCheckValueIsExist)
    {
        //辅助检查当天是否为第一次登录
        OnSetRedisAccountValue(strKeyCurrDate, strValueAccount);
        //统计在线用户
        OnHincrbyAccountLength(strHincrbyUserKeyDate, strHincrbyUserKeyDay);
    }
    return true;
}

//采用hincrby进行统计用户数
bool OnHincrbyAccountLength(string strHincrbyUserKeyDate,string strHincrbyUserKeyDay)
{

    redisContext* rConnectRServer = OnConnectRedisServer();
    if (rConnectRServer == NULL)
    {
        return false;
    }
    string command = "hincrby " + strHincrbyUserKeyDate + " " + strHincrbyUserKeyDay +" 1";
    redisReply* rReply = (redisReply*)redisCommand(rConnectRServer, command.c_str());
    CString cstrCommand = StrongString2Cstring(command);
    if (NULL == rReply)
    {
        XLogError(L"Hincrby写入数据失败(Command返回的应答对象指针为空){ Command:%s }",cstrCommand);
        redisFree(rConnectRServer);
        return false;
    }
    if (rReply->type == REDIS_REPLY_ERROR)
    {
        XLogError(L"Hincrby写入数据失败{ Command:%s }", cstrCommand);
        freeReplyObject(rReply);
        redisFree(rConnectRServer);
        return false;
    }
    freeReplyObject(rReply);
    redisFree(rConnectRServer);
    XLogInfo(L"Hincrby写入数据成功{ Command:%s }", cstrCommand);
    return true;
}

//设置key的生命周期  
bool SetKeyCurrDateExpire(string strKeyCurrDate, int expire, redisContext* context)
{
    redisContext* rConnectRServer = context;
    if (rConnectRServer == nullptr)
    {
        rConnectRServer = OnConnectRedisServer();
    }
    if (rConnectRServer == NULL)
    {
        return false;
    }
    char buf[10] = "";
    itoa(expire, buf, 10);
    string command = "expire " + strKeyCurrDate + " " + buf;
    redisReply* rReply = (redisReply*)redisCommand(rConnectRServer, command.c_str());
    if (rReply->type = REDIS_REPLY_INTEGER && rReply->integer == 1)
    {
        return true;
    }
    CString cstrKeyCurrDate = StrongString2Cstring(strKeyCurrDate);
    CString cstrCommand = StrongString2Cstring(command);
    XLogError(L"设置[%s]的生命周期[%d]失败{ Command:%s }", cstrKeyCurrDate, expire , cstrCommand);
    return false;
}

//string转换为cstring
CString StrongString2Cstring(string strData)
{
#ifdef _UNICODE  
        //如果是unicode工程  
        USES_CONVERSION; 
        CString cstrData(strData.c_str());
        return cstrData;
#else  
        //如果是多字节工程   
        //string 转 CString  
        CString cstrData;
        cstrData.Format("%s", strData.c_str());
        return cstrData;
#endif // _UNICODE    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值