我的项目--网页IM

项目名称:网页公共聊天室

项目简介:搭建HTTP服务器,实现网页版的网络聊天室,具有用户的注册,登录以及聊天功能。
项目实现框架图:
图片概述

项目概要设计:

首先基于MVC框架实现,设计三个模块:
1、数据管理模块:基于Mysql数据库进行用户信息管理;
2、业务处理模块:基于Mongoose库搭建HTTP服务器,处理登录注册请求以及切换WebSocket协议进行聊天;
3、前端界面模块:基于vue.js以及网页模板完成前端页面的操作功能

/

环境搭建:

1.g++编译器的升级

sudo yum install centos-release-scl-rh centos-release-scl
sudo yum install devtoolset-7-gcc devtoolset-7-gcc-C++
source /opt/rh/devtoolset-7/enable
echo “source /opt/rh/devtoolset-7/enable” > > ~/.bashrc

2.安装Mysql数据库
按照教程自己进行安装即可
3.安装mongoose http库
从github上clone:
git clone https://github.com/cesanta/mongoose.git
(如果克隆不下来就下载压缩包再给虚拟机复制就好)
4.安装jsoncpp库
sudo yum -y install epel-release
sudo yum install jsoncpp-devel

项目的模块设计(详细):

数据管理模块:

.
要管理的数据:用户信息,用户ID,用户名(账号),密码,状态(上线||下线),用户创建时间,最后一次下线时间(最后一次状态改变时间)
.
如何管理:基于Mysql数据库进行管理
表的设计:

creat table if not exists im_user(
id int primary key auto_increment comment '用户ID',
name varchar(32) comment '用户名', 
pass varchar(128) comment '加密后的密码串',
status int comment '状态, 0-下线,1-上线',
ctime datetime comment '用户创建时间' ,
stime datetime comment '用户最后一次状态改变时间')

.
要实现的功能:针对数据进行统一管理
用户新增,登录验证,获取用户状态,修改用户状态,修改用户密码

		MYSQL *MysqlInit();
		void MysqlDestory(MYSQL *mysql);
		bool MysqlQuery(MYSQL *mysql,const std::string &sql);
		class UserTable{
		private:
		MYSQL *_mysql;
		public:
		bool Insert(const std::string &name, const std::string &pass);//新增用户
		bool UserPassCheck(const std::string &name, const std::string &pass);//用户名密码验证
		int Status(int user_id);//获取用户状态,在线返回true,不在线返回false
		bool UpdateStatus(int user_id, int status);//修改用户状态
		bool UpdatePasswd(const std::string &name, const std::string &pass);//修改密码
		}
		
业务处理模块

.
1、搭建HTTP服务器,能够接受客户端的请求
基于mongoose库搭建服务器
.
2、针对客户端的请求进行业务处理
0、静态页面请求
1、用户注册功能(用户名是否已占用功能,数据新增功能)
2、用户登录功能(查看用户状态,用户名密码验证,修改用户状态)
3、网络聊天功能(消息广播–将消息逐个发送给所有聊天室客户端)
我们搭建的服务器是一个HTTP服务器,然而HTTP协议是一个简单的请求-响应协议,也就是说服务器是针对请求进行响应的,这时候如果有个客户端发送了一条消息,我们如何将消息发送给其他客户端
.
Ps:
1、每个客户端不断循环向服务器发送获取新消息功能(效率差,占用资源多,对服务器负载大),因此HTTP协议本质上并不适合用于这种广播聊天场景,因为它无法主动推送消息。
2、因此我们要在HTTP协议的基础上进行协议切换,切换为websocket协议进行聊天消息的传输
.
websocket协议是一个基于tcp的全双工通信协议,支持服务器主动推送数据,能更好的节省服务器资源和带宽,并且能够更实时的进行通讯
Websocket通过HTTP/1.1协议的101状态码进行握手

图片源于360百科,侵权联系即删

struct mg_mgr{
	struct mg_connection *conns;//活跃的连接链表--里边包含了所有的tcp新建套接字以及监听套接字
	void *userdata;//用户数据指针
	}//事件内务结构体
void mg_mgr_init(struct mg_mgr *mgr);用于初始化事件结构

struct mg_connection{
	struct mg_connection *next;//下一个节点的链表指针
	struct mg_mgr *mgr;//事件内务结构体指针
	void *fd;//套接字信息
	mg_event_handler_t fn;//用户指定的时间处理函数
	void *fn_data;//用户指定的回调函数参数
	unsigned is_websocket:1;//当前连接标志,判断是否是一个websocket连接
	}struct mg_connection*mg_http_listen(struct mg_mgr*mgr,const char*url,mg_event_handler_t fn,void *fn_data);
	ngr:mg_mgr_init初始化的句柄
	url:服务器监听的地址信息ip:port
	fn:事件回调函数---当某个连接接收到了数据,将使用这个函数进行处理
	fn_data:给回调函数传入的一个用户数据
	返回值:成功返回创建成功的HTTP连接
	如果有哪个链接有数据到来就会调用这个函数
void(*mg_event_handler_t)(struct mg_connection *conn, int ev, void*ev_data, void *fn_data);
	conn:传入时当前有数据到来的连接
	ev:当前连接所触发的事件
	ev_data:如果连接是一个http连接,则ev_data存储的就是http请求信息
struct mg_http_message{
	struct mg_str method,uri,query,proto;	//Request/response line
	struct mg_http_header headers[MG_MAX_HTTP_HEADERS]//Headers
	struct mg_str_body;	//Body
	struct mg_str message;	//Request line + headers + body
};
mg_mgr_poll(struct mg_mgr*mgr, int timeout)
开始所有连接的监听,内部使用的是poll完成所有套接字的事件监控,当描述符有数据,则这时候读取数据,进行解析,调入传入的回调函数

mongoose这个库并没有用到多线程和多进程,而是使用多路转接模型,进行IO事件监控,然后逐个连接进行请求处理。

mongoose库的处理流程:

1、初始化struct mg_mgr句柄结构(句柄中包含了一个连接链表,里边就是所有的活跃连接)
2、调用mg_http_listen()接口,内部创建了一个http连接–struct mg_connection,并且设置了fn成员为传入的回调函数,设置了pfn成员为http_cb回调函数
3、调用mg_mgr_poll()接口开始监控,内部是使用poll-多路转接模型进行io事件监控
当某个连接IO就绪:
若连接状态是listen状态,则获取新连接,添加到mg_mgr的链表中,并且给这个连接的fn和pfn成员也赋值回调函数
若状态是可读,非listen状态,则读取数据,放到封装的接收缓冲区中,调用pfn接口进行http解析
然后再调用fn成员函数----用户设置的回调函数(内部就是针对不用请求进行不同处理的过程)
回调函数处理完毕后,将连接的发送缓冲区中的数据进行响应给客户端

网络通信接口的设计:

什么样的数据是一个什么样的请求

HTTP请求类型:

.
静态页面请求
用户注册请求
用户登录请求
协议切换请求

WebSocket通信:

.
接收数据,进行广播

.

HTTP请求
业务处理模块代码设计:搭建网络通信服务器,进行业务处理

class IMServer{
	private:
		struct mg_mgr_mgr;	//mongoose服务器句柄
		static UserTable *_user_table;	//数据管理对象
		static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data)	//针对不同请求进行不同处理
	public:
		IMServer(){
			//句柄初始化,数据管理对象的构造
			mg_mgr_init(&_mgr);
			_user_table = new UserTable();
		}
		~IMServer(){
		//句柄释放,数据管理对象释放
		bool RunModule(int port){
			mg_http_listen(&mgr, "0.0.0.0:19000", cb, &_mgr);
		}
		};
}

总结:
1、session的管理:最好实现一个session的单例类,进行session的管理
2、使用ajax进行用户登录,不太合适,因为无法进行页面的正常重定向,需要手动重载chat.html页面,建议使用html的原生表单数据提交功能

项目源码

1、sql文件的导入(mysql-uroot -p):

  1 create database if not exists duck;
  2 
  3 use duck;
  4 
  5 create table if not exists im_user(
  6   id int primary key auto_increment,
  7   name varchar(32) not null,
  8   pass varchar(128) not null,                                                            
  9   status int comment '0-下线,1-在线',
 10   ctime datetime,
 11   stime datetime
 12 );
~

2、序列化反序列化测试:
vi util.hpp

#include<iostream>
#include<sstream>
#include<string>
#include<jsoncpp/json/json.h>
 
namespace im_sys{ 
  class JsonUtil{
   public:
       static bool Serialize(Json::Value &value,std::string *jsonstr)
       {
          std::stringstream ss;
          Json::StreamWriterBuilder swb;
          Json::StreamWriter *sw = swb.newStreamWriter();
          int ret = sw->write(value,&ss);
          if(ret !=0)
          {
           std::cout<<"json writer failed!\n";
           delete sw;
           return true;
          }
          *jsonstr = ss.str();
          delete sw;
          return true;
          }
          static bool UnSerialize(const std::string &jsonstr,Json::Value *value)
         {
         Json::CharReaderBuilder crb;
         Json::CharReader *cr = crb.newCharReader();
         std::string err;
         bool ret = cr->parse(jsonstr.c_str(),jsonstr.c_str() + jsonstr.size(),value,&err);
        if(ret == false)
         {
          delete cr;
          std::cout<<"json parse failed!"<<err<<std::endl;
          return false;
         }
          delete cr;
          return true;
     }
 };
} 

vi json_test.cpp

#include "util.hpp"
 int main()
 {
   std::string str = R"({"username":"wj","password":"1111"})";
   Json::Value val;
   im_sys::JsonUtil::UnSerialize(str,&val);
   std::cout<<val["username"].asString()<<std::endl;
   std::cout<<val["password"].asString()<<std::endl;
 
   Json::Value err;
   err["result"]=false;
   err["reason"] = "用户名已经被占用!";
   std::string buf;
   im_sys::JsonUtil::Serialize(err,&buf);
   std::cout<<buf<<std::endl;
 
   return 0;
}

server.hpp(注册等功能的实现):

#include "data.hpp"
#include "mongoose.h"
#include "util.hpp"
namespace im_sys{
#define SERVER_PORT 20000
 class Server
   {
    private:
         static struct mg_mgr *_mgr;
         static UserTable *_user;
   private:
           static void callback(struct mg_connection *c,int ev,void *ev_data,void *fn_data)
           {
             if(ev == MG_EV_HTTP_MSG)
             {
               struct mg_http_message *hm = (struct mg_http_message *)ev_data;
               if(mg_http_match_uri(hm,"/register"))
               {
                 // mg_http_reply(c,200,"","register success!");
                 // return;
                //拿到请求信息的正文,是json格式的用户信息,进行解析
                Json::Value user_info;
                JsonUtil::UnSerialize(hm->body.ptr,&user_info);
                std::string username = user_info["username"].asString();
                std::string password = user_info["password"].asString();
                          
                 //在数据库中进行查看用户名是否已经被占用
                 bool ret = _user->Exists(username);
                    if(ret == true)
                    {
                      Json::Value err;
                      err["result"] = false;
                      err["reason"] = "用户名已经被占用";
                      std::string body;
                      JsonUtil::Serialize(err,&body);
                      std::string header = "Content-Type:application/json\r\n";
                      mg_http_reply(c,400,header.c_str(),body.c_str());
                       return; 
                     }
                 //返回结果--注册成功或失败
                 ret = _user->Insert(username,password);
                    if(ret == false)
                    {
                       Json::Value err;
                       err["result"] = false;
                       err["reason"] = "用户插入数据库失败!";
                       std::string body;
                       JsonUtil::Serialize(err,&body);
                       std::string header = "Content-Type: application/json\r\n";                       mg_http_reply(c,200,header.c_str(),body.c_str());
                       return;
                    }
                    Json::Value err;
                    err["result"] = true;
                    err["reason"] = "注册成功!";
                    std::string body;
                    JsonUtil::Serialize(err,&body);
                    std::string header = "Content-Type:application/json\r\n";                    mg_http_reply(c,200,header.c_str(),body.c_str());
                       return;
           }
     }
  }
    public:
         Server()
         {
            _mgr = new struct mg_mgr();
            _user = new UserTable();
          }
 
        ~Server()
        {
          mg_mgr_free(_mgr);
          delete _mgr;
          delete _user;
        }
        bool RunModule(int port = SERVER_PORT)
        {
          std::string addr = "0.0.0.0:";
          addr += std::to_string(port);
          auto res = mg_http_listen(_mgr,addr.c_str(),callback,_mgr);
          if(res ==NULL)
           {
                std::cout<<"init http listen failed!\n";
                return false;
           }           
           while(1)
           {
              mg_mgr_poll(_mgr,1000);
           }
             return true;
            
         }    
   };
  struct mg_mgr *Server::_mgr = NULL;
  UserTable * Server::_user = NULL; 
 }

data.hpp:

#ifndef __M_IM_DATA_H__
#define __M_IM_DATA_H__
#include<iostream>
#include<string>
#include<cstdlib>
#include<mutex>
#include<mysql/mysql.h>
 
namespace im_sys{
#define DB_HOST "127.0.0.1"
#define DB_USER "root"
#define DB_PASS "1111"
#define DB_NAME "duck"
  static MYSQL *MysqlInit()
  {
    MYSQL *mysql = mysql_init(NULL);
    if(mysql == NULL)
    {
      std::cout<<"mysql init failed!\n";
      return NULL;
    }
    if(mysql_real_connect(mysql,DB_HOST,DB_USER,DB_PASS,DB_NAME,0,NULL,0) == NULL)
    {
     std::cout<<"connect mysql server failed:"<<mysql_error(mysql)<<std::endl;
     mysql_close(mysql);
     return NULL;
    }
     if(mysql_set_character_set(mysql,"utf8") != 0)
    {
     std::cout<<"set mysql client character failed!:"<<mysql_error(mysql)<<std::endl;
     mysql_close(mysql);
     return NULL;
    }
  return mysql;
}
  static void MysqlDestory(MYSQL *mysql)
  {
    if(mysql)
    {
      mysql_close(mysql);
    }
    return;
  }
 
  static bool MysqlQuery(MYSQL *mysql,const std::string &sql)
  {
   int ret = mysql_query(mysql,sql.c_str());
   if(ret != 0)
   {
     std::cout<<sql<<std::endl;
     std::cout<<"query failed:"<<mysql_error(mysql)<<std::endl;
     return false;
   }
  return true;
 }
 
  class UserTable{
 
    private:
         MYSQL *_mysql;
         std::mutex _mutex;
    public:
        UserTable():_mysql(NULL)
        {
         _mysql = MysqlInit();
         if(_mysql == NULL)
         {
          exit(-1);
         }
        }
 
        ~UserTable()
        {
           MysqlDestory(_mysql);
        }
        bool Insert(const std::string &name,const std::string &pass)
        {
         #define USER_INSERT "insert im_user values(null,'%s',MD5('%s'),0,now(),now());"
        char sql[4096] = {0};
        sprintf(sql,USER_INSERT,name.c_str(),pass.c_str());
        return MysqlQuery(_mysql,sql);
 
        }
 
     bool Exists(const std::string &name)
     {
       #define USER_EXISTS "select id from im_user where name='%s';"
       char sql[4096] = {0};
       sprintf(sql,USER_EXISTS,name.c_str());
       bool ret = MysqlQuery(_mysql,sql);
       if(ret == false)
       {
        return false;
       }
       MYSQL_RES *res = mysql_store_result(_mysql);
       int num = mysql_num_rows(res);
       if(num!=0)
        {
          mysql_free_result(res);
          return true;
        }
       mysql_free_result(res);
      return false;
    }
  
      bool UserPassCheck(const std::string &name,const std::string &pass)
     {
         #define USER_CHECK "select id from im_user where name='%s' and pass=MD5('%s');"
        char sql[4096] = {0};
        sprintf(sql,USER_CHECK,name.c_str(),pass.c_str());
        bool ret = MysqlQuery(_mysql,sql);
        if(ret == false)
         {
          return false;
         }
          MYSQL_RES *res = mysql_store_result(_mysql);
         int num = mysql_num_rows(res);
         if(num!=0)
          {
            mysql_free_result(res);
            return true;
          }
        mysql_free_result(res);
           return false;
     }
      int  Status(const std::string &name)
     {
      #define USER_STATUS "select status from im_user where name='%s';"
       char sql[4096]={0};
       sprintf(sql,USER_STATUS,name.c_str());
       bool ret = MysqlQuery(_mysql,sql);
       if(ret == false)
       {
         return false;
       }
       MYSQL_RES *res = mysql_store_result(_mysql);
       int num = mysql_num_rows(res);
       if(num == 0)
       {
         mysql_free_result(res);
          return -1;
       }
       MYSQL_ROW row = mysql_fetch_row(res);
       int status = std::stoi(row[0]);
       mysql_free_result(res);
       return status;
      }
     bool UpdateStatus(const std::string &name,int status)
     {
        #define USER_UPDATE_STATUS "update im_user set status=%d,stime=now() where name='%s';"
       char sql[4096] = {0};
       sprintf(sql,USER_UPDATE_STATUS,status,name.c_str());
       return MysqlQuery(_mysql,sql);
     }    
   
    bool UpdatePasswd(const std::string &name,const std::string &pass)
     {
       #define USER_UPDATE_PASS "update im_user set pass=MD5('%s') where name='%s';"
      char sql[4096] = {0};
      sprintf(sql,USER_UPDATE_PASS,pass.c_str(),name.c_str());
      return MysqlQuery(_mysql,sql);
   } 
   }; 
}
 
#endif  

main.cpp:

#include "data.hpp"
#include "server.hpp"
#define OFFLINE 0
#define ONLINE 1
void DataTest()
{
   im_sys::UserTable * _user = new im_sys::UserTable();
 
 	插入用户 
	_user->Insert("鸭鸭","111111");  
 
    测试用户是否存在
    bool ret = _user->Exists("鸭鸭");
    std::cout<<ret<<std::endl; 
 
    判断用户是否在线
    int status = _user->Status("鸭鸭");
    if(status ==ONLINE)
    {
    	std::cout<<"online user!\n";
    }
    else if(status == OFFLINE)
    {
    	std::cout<<"offline user!\n";
    }
 
   修改用户状态
   _user->UpdateStatus("鸭鸭",OFFLINE);
  
   int status = _user->Status("鸭鸭");
   if(status ==ONLINE)
   {
    	std::cout<<"online user!\n";
   }
   else if(status == OFFLINE)
   {
       std::cout<<"offline user!\n";
   }
 
   检验密码
   bool ret = _user->UserPassCheck("鸭鸭","111111");
   if(ret == false)
   {
   		std::cout<<"用户名密码错误!\n";
   }
   else 
   {
   		std::cout<<"login success!\n";
   }
   }
 
   修改密码
   _user->UpdatePasswd("王五","1111");
   int ret =_user->UserPassCheck("王五","1111");
  
   if(ret == false)
   {
    	std::cout<<"用户名密码错误!\n";
   }
   else 
   {
    	std::cout<<"login success!\n";
   }
 } 
 
void ServerTest()
{
  	im_sys::Server *server = new im_sys::Server();
  	server->RunModule();
  	return;
}
 
int main()
{
 	DataTest();
 	ServerTest();
 	return 0;
}

makefile:

main:data.hpp main.cpp
	g++ -std=c++11 $^ -o $@ -L/usr/lib64/mysql  -lmysqlclient -L./lib -lmongoose -ljsoncpp

server.hpp

#include "data.hpp"
#include "mongoose.h"
#include "util.hpp"
#include <unordered_map>
#include <time.h>
namespace im_sys{
#define SERVER_PORT 20000
#define OFFLINE 0
#define ONLINE 1
#define WWWROOT "./wwwroot/"
 
struct IMSession
{
   int status;
   std::string session_id;//系统时间
   std::string username;
   time_t ctime;//会话创建时间
   time_t ltime;//最后操作时间
   struct mg_connection *conn;//当前用户对一个的mongoose连接
}; 
 
 class Server
   {
    private:
         static struct mg_mgr *_mgr;
         static UserTable *_user;
         static std::unordered_map<std::string,IMSession> _session;
   private:
         static std::string ConResp(bool res,const std::string &info)
          {
           Json::Value err;
           err["result"] = res;
           err["reason"] = info;
           std::string body;
           JsonUtil::Serialize(err,&body);
           return body;
           }
 
         static  std::string CreateIMSession(struct mg_connection *c,const std::string &username)
           {
             struct IMSession s;
             s.conn = c;
             s.username = username;
             s.status = ONLINE;
             s.ctime = time(NULL);
             s.ltime = time(NULL);
             s.session_id = std::to_string(time(NULL));
             _session[s.session_id] = s;
             return s.session_id;
           }
 
 
           static void Login(struct mg_connection *c,struct mg_http_message *hm)
          {
             //拿到请求正文,进行json反序列化得到用户名和密码
             Json::Value user_info;
             JsonUtil::UnSerialize(hm->body.ptr,&user_info);
             std::string username = user_info["username"].asString();
             std::string password = user_info["password"].asString();
            //在数据库中验证用户名和密码
             bool ret = _user->UserPassCheck(username,password);
            if(ret == false)
              {
                std::string body = ConResp(false,"用户名密码错误");
                std::string header = "Content-Type: application/json\r\n";
                mg_http_reply(c,400,header.c_str(),body.c_str());
                return;
             }
 
            //判断用户是否已经在线,若已经在线,则不能重复登录
               ret = _user->Status(username);
               if(ret == ONLINE)
              {
                std::string body = ConResp(false,"用户已登录");
                std::string header = "Content-Type: application/json\r\n";
                mg_http_reply(c,400,header.c_str(),body.c_str());
                return;
               }
            //没在线,则修改用户为在线状态,并且返回登录成功,设置SetCookie包括用户名、用户状态
            std::string ssid =  CreateIMSession(c,username);
            ret = _user->UpdateStatus(username,ONLINE);
            if(ret == false)
            {
              std::string body = ConResp(false,"修改用户状态失败");
              std::string header = "Content-Type: application/json\r\n";
              mg_http_reply(c,500,header.c_str(),body.c_str());
               return;
            }
 
            //登录成功需要让客户端去请求一个聊天页面
            std::stringstream headers;
            headers<< "Location: /chat.html\r\n";
            headers <<"Set-Cookie: SSID=" <<ssid<<";Path=/\r\n";
           
            std::string body = ConResp(true,"登录成功");
            mg_http_reply(c,302,headers.str().c_str(),body.c_str());
            return;
      }
 
           static void  Register(struct mg_connection *c,struct mg_http_message *hm)
          {
     
                //拿到请求信息的正文,是json格式的用户信息,进行解析
                Json::Value user_info;
                JsonUtil::UnSerialize(hm->body.ptr,&user_info);
                std::string username = user_info["username"].asString();
                std::string password = user_info["password"].asString();
                 
         
                 //在数据库中进行查看用户名是否已经被占用
                 bool ret = _user->Exists(username);
                    if(ret == true)
                    {
                      Json::Value err;
                      err["result"] = false;
                      err["reason"] = "用户名已经被占用";
                      std::string body;
                      JsonUtil::Serialize(err,&body);
                      std::string header = "Content-Type:application/json\r\n";
                      mg_http_reply(c,400,header.c_str(),body.c_str());
                       return; 
                     }
                 //返回结果--注册成功或失败
                 ret = _user->Insert(username,password);
                    if(ret == false)
                    {
                       Json::Value err;
                       err["result"] = false;
                       err["reason"] = "用户插入数据库失败!";
                       std::string body;
                       JsonUtil::Serialize(err,&body);
                       std::string header = "Content-Type: application/json\r\n";
                       mg_http_reply(c,200,header.c_str(),body.c_str());
                       return;
                    }
                    Json::Value err;
                    err["result"] = true;
                    err["reason"] = "注册成功!";
                    std::string body;
                    JsonUtil::Serialize(err,&body);
                    std::string header = "Content-Type:application/json\r\n";
                    mg_http_reply(c,200,header.c_str(),body.c_str());
                       return;
          }
 
          static bool GetSession(struct mg_connection *c,IMSession *session)
           {
              auto it = _session.begin();
              for(;it!=_session.end();++it)
              {
                if(it->second.conn == c)
                  {
                    *session = it->second;
                     return true;
                   }
               }
            return false;
           }
 
           static bool DelSession(IMSession &session)
           {
             auto it = _session.find(session.session_id);
             if(it == _session.end())
             {
               std::cout<<"not find session\n";
               return false;
             }
            _session.erase(it);
            return true;
            }
 
 
 
            static void ConnClose(struct mg_connection *c)
           {
             //找到连接对应的session
              IMSession session;
             bool ret = GetSession(c,&session);
             if(ret == false)
             {
                std::cout<<"have no session info!\n";
                return;
             }
             //修改数据库中的用户状态
              ret = _user->UpdateStatus(session.username,OFFLINE);
              if(ret == false)
              {
               std::cout<<"update status offline failed!\n";
               return;
              }
             //删除会话信息
              DelSession(session);
              } 
 
           static void callback(struct mg_connection *c,int ev,void *ev_data,void *fn_data)
           {
             if(ev == MG_EV_HTTP_MSG)
             {
               struct mg_http_message *hm = (struct mg_http_message *)ev_data;
                 if(mg_http_match_uri(hm,"/register"))
                 {
                   // mg_http_reply(c,200,"","register success!");
                   // return;
                   Register(c,hm);
                 }
                 else if(mg_http_match_uri(hm,"/login"))
                 {
                   //登录请求
                     Login(c,hm);
                 }
                 else if(mg_http_match_uri(hm,"/cws"))
                 {
                   //协议切换请求
                 }
                 else
                 {
                    //静态页面请求
                      struct mg_http_serve_opts opts = {.root_dir = WWWROOT};
                      mg_http_serve_dir(c,hm,&opts);
                 }
            }
            else if(ev == MG_EV_WS_OPEN)
              {
                //websocket握手成功
 
              }
            else if(ev == MG_EV_WS_MSG)
              {
                //收到聊天消息
              }
            else if(ev == MG_EV_CLOSE)
              {
                //表示连接断开
                 ConnClose(c); 
              } 
  }
 
   
    public:
         Server()
         {
            _mgr = new struct mg_mgr();
            _user = new UserTable();
          }
 
        ~Server()
        {
          mg_mgr_free(_mgr);
          delete _mgr;
          delete _user;
 
        }
        bool RunModule(int port = SERVER_PORT)
        {
          std::string addr = "0.0.0.0:";
          addr += std::to_string(port);
          auto res = mg_http_listen(_mgr,addr.c_str(),callback,_mgr);
          if(res ==NULL)
           {
                std::cout<<"init http listen failed!\n";
                return false;
           }
           
            while(1)
            {
              mg_mgr_poll(_mgr,1000);
            }
             return true;
            
         }
   
         
        
   };
  struct mg_mgr *Server::_mgr = NULL;
  UserTable * Server::_user = NULL;
  std::unordered_map<std::string,IMSession>Server::_session;
 
 }

网页IM
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值