errorbeep@home:~$

用户登录(c++, mysql)


接上篇:注册用户(c++, mysql)。实现用户登录功能,客户端负责收集用户登录信息并发送至服务端,服务端将接收到的消息与其在mysql数据库中存储的信息核对,核对后通知客户端该用户可否登录,客户端进一步处理。

实现客户端的任务比较简单,客户端启动后与服务端建立连接,提示用户选择何种操作,若用户选择登录,则进入负责收集并发送登录信息和接收服务端应答的逻辑,若服务端核对用户信息无误则提示用户登录成功,并让用户选择后续操作;

具体实现:

void client::HandleClient(int conn){
    int choice;
    string name,pass,pass1;
    bool if_login=false;//记录是否登录成功
    string login_name;//记录成功登录的用户名

    cout<<" ------------------\n";
    cout<<"|                  |\n";
    cout<<"| 请输入你要的选项:|\n";
    cout<<"|    0:退出        |\n";
    cout<<"|    1:登录        |\n";
    cout<<"|    2:注册        |\n";
    cout<<"|                  |\n";
    cout<<" ------------------ \n\n";

    //开始处理注册、登录事件
    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;
                    cout<<"登录成功\n\n";
                    break;
                }
                //登录失败
                else
                    cout<<"密码或用户名错误!\n\n";
            }
        }
    }
    //登录成功
    if(if_login){
        system("clear");//清空终端d
        cout<<"        欢迎回来,"<<login_name<<endl;
        cout<<" -------------------------------------------\n";
        cout<<"|                                           |\n";
        cout<<"|          请选择你要的选项:               |\n";
        cout<<"|              0:退出                       |\n";
        cout<<"|              1:发起单独聊天               |\n";
        cout<<"|              2:发起群聊                   |\n";
        cout<<"|                                           |\n";
        cout<<" ------------------------------------------- \n\n";
    }
}

服务端与客户端建立连接后创建线程接收客户端请求,创建函数handleRequests集中处理这些请求,handleRequests首先要判断是何种请求,然后针对特定请求做相应处理,最后应答客户端;
来自客户端的请求可以作为参数传入handleRequests函数,例外此函数需要应答客户端所以还要将客户端的套接字描述符作为参数传入;
对于客户端发送的请求可以用子串匹配的函数确定是哪种请求,之后使用提取子串的函数解析请求,对于登录请求而言,需要将解析得到的登录信息即用户名和密码保存起来以和数据库中存放的信息核对,如果信息无误则传回“ok“,否则”wrong“; 对于信息的核对工作:

  1. 先建立与mysql数据库的连接;C++连接mysql
  2. 构造sql查询语句查询数据库中用户名与登录信息相符的记录;
    ==> int mysql_query(MYSQL *mysql, const char *query)
  3. 存储查询得到的结果集;
    ==> MYSQL_RES *mysql_store_result(MYSQL *mysql)
  4. 获取结果集中的行数,确保不仅查询成功且得到的不是空结果集;
    ==> my_ulonglong mysql_num_rows(MYSQL_RES *result)
  5. 如果得到的是空结果集则登录信息错误,判断结束;
  6. 获取结果集的下一行;
    ==> MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
  7. 获取该行用户名字段和密码字段的值;
  8. 若密码与登录信息的密码相同则登录信息无误;

具体实现:

void server::HandleRequest(int conn,string str){
    char buffer[1000];
    string name,pass;
    bool if_login=false;//记录当前服务对象是否成功登录
    string login_name;//记录当前服务对象的名字
    //string target_name;//记录发送信息时目标用户的名字
    //int group_num;//记录群号


    //连接MYSQL数据库
    MYSQL *con=mysql_init(NULL);
    mysql_real_connect(con,"127.0.0.1","root","","ChatProject",0,NULL,CLIENT_MULTI_STATEMENTS);

    //注册
    if(str.find("name:")!=str.npos){
        int p1=str.find("name:"),p2=str.find("pass:");
        name=str.substr(p1+5,p2-5);
        pass=str.substr(p2+5,str.length()-p2-4);
        string search="INSERT INTO USER VALUES (\"";
        search+=name;
        search+="\",\"";
        search+=pass;
        search+="\");";
        cout<<"sql语句:"<<search<<endl<<endl;
        mysql_query(con,search.c_str());
    }
    //登录
    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;//记录下当前登录的用户名
                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);
        }
    }
}

下一篇:私聊(互斥锁, map, tuple)