记录登录状态的功能的实现

1.Redis相关介绍;

C++连接redis工具:
hiredis安装

cd /home/shiyanlou
wget https://github.com/redis/hiredis/archive/v0.14.0.tar.gz
tar -xzf v0.14.0.tar.gz
cd hiredis-0.14.0/
make
sudo make install

##复制路径
sudo cp /usr/local/lib/libhiredis.so.0.14 /usr/lib/

测试程序:

#include <iostream>
#include <hiredis/hiredis.h>
using namespace std;
int main(){
    redisContext *c = redisConnect("127.0.0.1",6379);
    if(c->err){
       redisFree(c);
       cout<<"连接失败"<<endl;
       return 1;
    }
    cout<<"连接成功"<<endl;
    redisReply *r = (redisReply*)redisCommand(c,"PING");
    cout<<r->str<<endl;
    return 0;
}

打开redis:

cd /usr/bin
./redis-server

打开新终端:

g++ -o test_redis test_redis.cpp -lhiredis
./test_redis##运行程序

在这里插入图片描述
hiredis常见API

2 服务端

2.1 功能概述:

利用 Redis 记录用户登录状态(HASH 类型,键为 sessionid,值为 session 对象,键五分钟后过期),当用户成功登录时服务器会利用随机算法生成 sessionid 发送到客户端保存,客户登录时会优先发送 sessionid到服务器检查,如果检查通过就不用输入账号密码登录。

2.2头文件添加:

global.h

#ifndef _GLOBAL_H
#define _GLOBAL_H

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#include <thread>
#include <vector>
#include <mysql/mysql.h>
#include <unordered_map>
#include <pthread.h>
#include <set>
#include <hiredis/hiredis.h>    //补充
using namespace std;

#endif

2.3HandleRequest代码修改:

  1. redis的连接:
//连接redis数据库
redisContext *redis_target = redisConnect("127.0.0.1",6379);
if(redis_target->err){
    redisFree(redis_target);
    cout<<"连接redis失败"<<endl;
}
  1. 查看是否存在session
//先接收cookie看看redis是否保存该用户的登录状态
if(str.find("cookie:")!=str.npos){
    string cookie=str.substr(7);
    // 查询该cookie是否存在:hget cookie name
    string redis_str="hget "+cookie+" name";
    redisReply *r = (redisReply*)redisCommand(redis_target,redis_str.c_str());
    string send_res;
    //存在
    if(r->str){
        cout<<"查询redis结果:"<<r->str<<endl;
        send_res=r->str;
    }
    //不存在
    else
        send_res="NULL";
    send(conn,send_res.c_str(),send_res.length()+1,0);
}
  1. 生成sessionId并发送
    生成SessionId算法:10位sessionid,每位由大写字母小写字母以及数字中随机生成;
//登录
else if(str.find("login")!=str.npos){
    int p1=str.find("login"),p2=str.find("pass:");
    name=str.substr(p1+5,p2-5);
    pass=str.substr(p2+5,str.length()-p2-4);
    string search="SELECT * FROM USER WHERE NAME=\"";
    search+=name;
    search+="\";";
    cout<<"sql语句:"<<search<<endl;
    auto search_res=mysql_query(con,search.c_str());
    auto result=mysql_store_result(con);
    int col=mysql_num_fields(result);//获取列数
    int row=mysql_num_rows(result);//获取行数
    //查询到用户名
    if(search_res==0&&row!=0){
        cout<<"查询成功\n";
        auto info=mysql_fetch_row(result);//获取一行的信息
        cout<<"查询到用户名:"<<info[0]<<" 密码:"<<info[1]<<endl;
        //密码正确
        if(info[1]==pass){
            cout<<"登录密码正确\n\n";
            string str1="ok";
            if_login=true;
            login_name=name;
            pthread_mutex_lock(&name_sock_mutx); //上锁
            name_sock_map[login_name]=conn;//记录下名字和文件描述符的对应关系
            pthread_mutex_unlock(&name_sock_mutx); //解锁

            // 随机生成sessionid并发送到客户端
            srand(time(NULL));//初始化随机数种子
            for(int i=0;i<10;i++){
                int type=rand()%3;//type为0代表数字,为1代表小写字母,为2代表大写字母
                if(type==0)
                    str1+='0'+rand()%9;
                else if(type==1)
                    str1+='a'+rand()%26;
                else if(type==2)
                    str1+='A'+rand()%26;
            }
            //将sessionid存入redis
            string redis_str="hset "+str1.substr(2)+" name "+login_name;
            redisReply *r = (redisReply*)redisCommand(redis_target,redis_str.c_str());
            //设置生存时间,默认300秒
            redis_str="expire "+str1.substr(2)+" 300";
            r=(redisReply*)redisCommand(redis_target,redis_str.c_str());
            cout<<"随机生成的sessionid为:"<<str1.substr(2)<<endl;

            send(conn,str1.c_str(),str1.length()+1,0);
        }
        //密码错误
        else{
            cout<<"登录密码错误\n\n";
            char str1[100]="wrong";
            send(conn,str1,strlen(str1),0);
        }
    }
    //没找到用户名
    else{
        cout<<"查询失败\n\n";
        char str1[100]="wrong";
        send(conn,str1,strlen(str1),0);
    }
}

3.客户端

3.1 功能概述

大致步骤:在本地创建cookie.txt 文件存储sessionId;
第一次登录,接受sessionid存储至cookie.txt当中;

将其发送至服务端,和redis 中数据进行对比;
由服务端发送结果到客户端;
若对比成功,则直接登录成功;

3.2对比sessionId;

ifstream f("cookie.txt");
string cookie_str;
if(f.good()){
    f>>cookie_str;
    f.close();
    cookie_str="cookie:"+cookie_str;
    //将cookie发送到服务器
    send(sock,cookie_str.c_str(),cookie_str.length()+1,0);
    //接收服务器答复
    char cookie_ans[100];
    memset(cookie_ans,0,sizeof(cookie_ans));
    recv(sock,cookie_ans,sizeof(cookie_ans),0);
    //判断服务器答复是否通过
    string ans_str(cookie_ans);
    if(ans_str!="NULL"){//redis查询到了cookie,通过
        if_login=true;
        login_name=ans_str;
    }

3.3登录新建cookie.txt

 //开始处理注册、登录事件
    while(1){
        if(if_login)
           break;
        cin>>choice;
        if(choice==0)
            break;
        //注册
        else if(choice==2){
            cout<<"注册的用户名:";
            cin>>name;
            while(1){
                cout<<"密码:";
                cin>>pass;
                cout<<"确认密码:";
                cin>>pass1;
                if(pass==pass1)
                    break;
                else
                    cout<<"两次密码不一致!\n\n";
            }
            name="name:"+name;
            pass="pass:"+pass;
            string str=name+pass;
            send(conn,str.c_str(),str.length(),0);
            cout<<"注册成功!\n";
            cout<<"\n继续输入你要的选项:";
        }
        //登录
        else if(choice==1&&!if_login){
            while(1){
                cout<<"用户名:";
                cin>>name;
                cout<<"密码:";
                cin>>pass;
                string str="login"+name;
                str+="pass:";
                str+=pass;
                send(sock,str.c_str(),str.length(),0);//发送登录信息
                char buffer[1000];
                memset(buffer,0,sizeof(buffer));
                recv(sock,buffer,sizeof(buffer),0);//接收响应
                string recv_str(buffer);
                if(recv_str.substr(0,2)=="ok"){
                    if_login=true;
                    login_name=name;
                    string tmpstr=recv_str.substr(2);
                    tmpstr="cat > cookie.txt <<end \n"+tmpstr+"\nend";
                    system(tmpstr.c_str());



                    cout<<"登陆成功\n\n";
                    break;
                }
                else
                    cout<<"密码或用户名错误!\n\n";
            }       
        }
    }
    //登陆成功
    while(if_login&&1)```
## 4 功能展示;
服务端
![在这里插入图片描述](https://img-blog.csdnimg.cn/0952f357597843d991329a9fdba01bfa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiJ4oWm,size_20,color_FFFFFF,t_70,g_se,x_16)
客户端:
![在这里插入图片描述](https://img-blog.csdnimg.cn/fb2619ce366a4ed7ab9372b3e99a9fe8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiJ4oWm,size_19,color_FFFFFF,t_70,g_se,x_16)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值