libevent+QT即时通信项目——服务器注册功能

通信

5.服务器-注册功能

1.类型描述,数据采用JSON格式

步骤:

在这里插入图片描述

数据:

在这里插入图片描述

2.Ubuntu安装jsoncpp

  1. sudo apt-get install libjsoncpp-dev
  2. ls /usr/include/jsoncpp/json/ 检查是否安装成功
  3. 使用的时候包含头文件#include <jsoncpp/json/json.h>
  4. 第三步编译的时候链接库g++ -ljsoncpp

3.数据库写数据

在这里插入图片描述

每个用户都是一个表,表名就是用户名,里面存放的是password和friend

create table 肥猪 (password varchar(16), friend varchar(4096));
show tables like '肥猪';
insert into 肥猪 (password) values("000000");

4.数据库检索用户是否存在和添加用户

chat_databases.h .cpp

#.h
class ChatDataBases
{
    bool my_database_user_exist(const std::string name); //注册时判断用户是否存在

    void my_database_add_user(const std::string name, const std::string password); //注册添加用户

};

**********************************************************************
#.cpp       
bool ChatDataBases::my_database_user_exist(const std::string name)
{
    //先设置中文
    if (mysql_query(mysql,"set names utf8") != 0)
    {
        std::cout << "mysql_query error" << std::endl;
    }

    //封装sql语句
    char sql[128] = {0};
    sprintf(sql,"show tables like '%s';",name.c_str()); //sprintf接收的是char *
    if (mysql_query(mysql,sql) != 0 )
    {
        std::cout << "mysql_query error " << std::endl;
    }

    //查询结果
    MYSQL_RES *res = mysql_store_result(mysql);
    MYSQL_ROW row = mysql_fetch_row(res);

    if (row)         //不为空 存在该用户
    {
        return true;
    }
    else             //为空 不存在该用户
    {
        return false;
    }
}

void ChatDataBases::my_database_add_user(const std::string name, const std::string password)
{
    //创建表
    char sql[128] = {0};
    sprintf(sql,"create table %s (password varchar(16), friend varchar(4096));",name.c_str()); //sprintf接收的是char *
    if (mysql_query(mysql,sql) != 0 )
    {
        std::cout << "mysql_query error" << std::endl;
    }

    //往表插入数据,这里没有好友字段,因为刚注册是不会有好友的,直接写password就行
    memset(sql, 0 , sizeof(sql));
    sprintf(sql, "insert into %s (password) values('%s');",name.c_str(), password.c_str());
    if (mysql_query(mysql,sql) != 0 )
    {
        std::cout << "mysql_query error" << std::endl;
    }
}    

5.服务器根据数据库检查结果返回数据给客户端

server.h .cpp

#include "chatlist.h"
#include "chat_databases.h"

class Server
{
private:
    static ChatDataBases *mydatabase;   //数据库对象
    static void server_register(struct bufferevent *bev, const Json::Value val);
};

********************************************************************
    
#.cpp 这里有修改,之前的代码有内存泄露问题 base 和 bev 的释放时机不对
//线程函数一般没有返回值
void Server::client_handle(int fd)
{
    //创建集合,这个是工作集合
    struct event_base * base = event_base_new();

    //创建bufferevent对象,并与base绑定
    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    if (bev == NULL)
    {
        printf("bufferevent_socket_new error \n");
    }
    
    //给bufferevent设置回调函数
    bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL);

    //使能回调函数
    bufferevent_enable(bev,EV_READ);

    //监听
    event_base_dispatch(base);

    //释放,不放这里,因为只有当客户端断开连接或者出现异常时才释放,在event_cb中写
    //event_base_free(base);
    //bufferevent_free(bev);
}

//读取数据,客户端发送过来的数据,注册,登录那些都在这里写
void Server::read_cb(struct bufferevent *bev, void *ctx)
{
    char buf[1024] = {0};
    int size = bufferevent_read(bev, buf, sizeof(buf));
    if (size < 0)
    {
        std::cout << "bufferevent_read error \n" << std::endl;
    }
    else
    {
        std::cout << "传过来的数据:" << buf << std::endl;
    }

    /*
    数据的传送采用josn的格式,后面下面进行解析数据,然后
    进行实现不同的功能,注册登录那些
    */
    
   Json::Reader reader;     //解析json对象
   Json::FastWriter writer;     //封装json对象
   Json::Value val;         //json对象

   if (!reader.parse(buf, val)) //把字符串转换成json对象
   {
        std::cout << "服务器解析数据失败!Json::Reader parse error "<<std::endl;
   }

   std::string cmd = val["cmd"].asString(); //通过键解析键值

   if (cmd == "register")  //注册功能
   {
        server_register(bev, val); //要往bev写入数据,val是上面buf转换成json的数据
   }
   else
   {


   }
   
}

//在异常情况下或者客户端断开连接时,会触发event_cb函数调用
void Server::event_cb(struct bufferevent *bev, short what, void *ctx)
{
        // 释放bufferevent对象
    bufferevent_free(bev);
    
    // 释放event_base对象
    struct event_base *base = bufferevent_get_base(bev);
    event_base_loopbreak(base);
    event_base_free(base);

}


void Server::server_register(struct bufferevent *bev, const Json::Value val)
{
    //先连接数据库,记得断开
    mydatabase->my_database_connect("user");

    //检查数据库是否有这个用户,这里在数据库操作里面写就好,只需要知道结果就行
    if (mydatabase->my_database_user_exist(val["user"].asString())) //用户存在,返回客户端注册失败
    {
        //返回的JSON格式数据
        Json::Value val;
        val["cmd"] = "register_reply";
        val["result"] = "failure";

        //返回给客户端,用bev
        // const char* data= Json::FastWriter().write(val).c_str(); //val在这个过程中被释放了,data是空值
        std::string data = Json::FastWriter().write(val);
        if(bufferevent_write(bev, data.c_str(), strlen(data.c_str())) < 0)
        {
            std::cout << "bufferevent_write error" << std::endl;
        }
    }
    else    //用户不存在,不存在就写入数据库当中,返回客服端完成注册                                               
    {
        //写入数据库
        mydatabase->my_database_add_user(val["user"].asString(), val["password"].asString());

        //返回的JSON格式数据
        Json::Value val;
        val["cmd"] = "register_reply";
        val["result"] = "success";

        //返回给客户端,用bev
        std::string data = Json::FastWriter().write(val);
        if(bufferevent_write(bev, data.c_str(), strlen(data.c_str())) < 0)
        {
            std::cout << "bufferevent_write error" << std::endl;
        }
    }
    
    //
    mydatabase->my_database_disconnect();
}    

6.测试

要安装json-c,https://blog.csdn.net/qq_52201535/article/details/133581163

client_test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <json-c/json.h>

int main()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        perror("socket error");
        exit(1);
    }
    
    struct sockaddr_in server_addr;
    memset(&server_addr, 0 , sizeof(server_addr));//情空
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.24.149");
    server_addr.sin_port = htons(8000);
    
    //向服务器发起连接
    int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret == -1)
    {
        perror("connect error");
        exit(1);
    }


    //char buf[320] = "{'cmd':'register','user':'肥猪','password':'001227'};";
    struct json_object *obj = json_object_new_object();
    json_object_object_add(obj, "cmd", json_object_new_string("register"));
    json_object_object_add(obj, "user", json_object_new_string("肥猪"));
    json_object_object_add(obj, "password", json_object_new_string("001227"));

    const char *buf = json_object_to_json_string(obj);
    ret = send(sockfd, buf, strlen(buf), 0);
    if (ret == -1)
    {
        perror("send error");
        exit(1);
    }
    char s[128] = {0};
    ret = recv(sockfd, s, sizeof(s), 0);
    printf("收到服务器回复:%s\n",s);

    close(sockfd);
    return 0;
}

编译:gcc client_test.c -o client_test -ljson-c

结果:
在这里插入图片描述
删除表drop table 肥猪;后再试一次
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值