• 项目网页聊天室


    目录

    1.ubuntu导入sql文件

     2.用.c文件生成库文件

     3.序列化 反序列化测试

    4. 第一次用postman测试注册功能

    5.用postman测试用户登录成功后跳转页面 ---302

     6.项目网页聊天室总结


    1.ubuntu导入sql文件

    sql文件:

     使用命令mysql -uroot -p

    结果如下:

     2.用.c文件生成库文件

     3.序列化 反序列化测试

    vi util.hpp:

    1. #include
    2. #include
    3. #include
    4. #include
    5. namespace im_sys{
    6. class JsonUtil{
    7. public:
    8. static bool Serialize(Json::Value &value,std::string *jsonstr)
    9. {
    10. std::stringstream ss;
    11. Json::StreamWriterBuilder swb;
    12. Json::StreamWriter *sw = swb.newStreamWriter();
    13. int ret = sw->write(value,&ss);
    14. if(ret !=0)
    15. {
    16. std::cout<<"json writer failed!\n";
    17. delete sw;
    18. return true;
    19. }
    20. *jsonstr = ss.str();
    21. delete sw;
    22. return true;
    23. }
    24. static bool UnSerialize(const std::string &jsonstr,Json::Value *value)
    25. {
    26. Json::CharReaderBuilder crb;
    27. Json::CharReader *cr = crb.newCharReader();
    28. std::string err;
    29. bool ret = cr->parse(jsonstr.c_str(),jsonstr.c_str() + jsonstr.size(),value,&err);
    30. if(ret == false)
    31. {
    32. delete cr;
    33. std::cout<<"json parse failed!"<
    34. return false;
    35. }
    36. delete cr;
    37. return true;
    38. }
    39. };
    40. }

    vi json_test.cpp:

    1. #include "util.hpp"
    2. int main()
    3. {
    4. std::string str = R"({"username":"wj","password":"1111"})";
    5. Json::Value val;
    6. im_sys::JsonUtil::UnSerialize(str,&val);
    7. std::cout<"username"].asString()<
    8. std::cout<"password"].asString()<
    9. Json::Value err;
    10. err["result"]=false;
    11. err["reason"] = "用户名已经被占用!";
    12. std::string buf;
    13. im_sys::JsonUtil::Serialize(err,&buf);
    14. std::cout<
    15. return 0;
    16. }

    测试结果:

    4. 第一次用postman测试注册功能

    server.hpp  ---/register功能的相应实现

    1. #include "data.hpp"
    2. #include "mongoose.h"
    3. #include "util.hpp"
    4. namespace im_sys{
    5. #define SERVER_PORT 20000
    6. class Server
    7. {
    8. private:
    9. static struct mg_mgr *_mgr;
    10. static UserTable *_user;
    11. private:
    12. static void callback(struct mg_connection *c,int ev,void *ev_data,void *fn_data)
    13. {
    14. if(ev == MG_EV_HTTP_MSG)
    15. {
    16. struct mg_http_message *hm = (struct mg_http_message *)ev_data;
    17. if(mg_http_match_uri(hm,"/register"))
    18. {
    19. // mg_http_reply(c,200,"","register success!");
    20. // return;
    21. //拿到请求信息的正文,是json格式的用户信息,进行解析
    22. Json::Value user_info;
    23. JsonUtil::UnSerialize(hm->body.ptr,&user_info);
    24. std::string username = user_info["username"].asString();
    25. std::string password = user_info["password"].asString();
    26. //在数据库中进行查看用户名是否已经被占用
    27. bool ret = _user->Exists(username);
    28. if(ret == true)
    29. {
    30. Json::Value err;
    31. err["result"] = false;
    32. err["reason"] = "用户名已经被占用";
    33. std::string body;
    34. JsonUtil::Serialize(err,&body);
    35. std::string header = "Content-Type:application/json\r\n";
    36. mg_http_reply(c,400,header.c_str(),body.c_str());
    37. return;
    38. }
    39. //返回结果--注册成功或失败
    40. ret = _user->Insert(username,password);
    41. if(ret == false)
    42. {
    43. Json::Value err;
    44. err["result"] = false;
    45. err["reason"] = "用户插入数据库失败!";
    46. std::string body;
    47. JsonUtil::Serialize(err,&body);
    48. std::string header = "Content-Type: application/json\r\n";
    49. mg_http_reply(c,200,header.c_str(),body.c_str());
    50. return;
    51. }
    52. Json::Value err;
    53. err["result"] = true;
    54. err["reason"] = "注册成功!";
    55. std::string body;
    56. JsonUtil::Serialize(err,&body);
    57. std::string header = "Content-Type:application/json\r\n";
    58. mg_http_reply(c,200,header.c_str(),body.c_str());
    59. return;
    60. }
    61. }
    62. }
    63. public:
    64. Server()
    65. {
    66. _mgr = new struct mg_mgr();
    67. _user = new UserTable();
    68. }
    69. ~Server()
    70. {
    71. mg_mgr_free(_mgr);
    72. delete _mgr;
    73. delete _user;
    74. }
    75. bool RunModule(int port = SERVER_PORT)
    76. {
    77. std::string addr = "0.0.0.0:";
    78. addr += std::to_string(port);
    79. auto res = mg_http_listen(_mgr,addr.c_str(),callback,_mgr);
    80. if(res ==NULL)
    81. {
    82. std::cout<<"init http listen failed!\n";
    83. return false;
    84. }
    85. while(1)
    86. {
    87. mg_mgr_poll(_mgr,1000);
    88. }
    89. return true;
    90. }
    91. };
    92. struct mg_mgr *Server::_mgr = NULL;
    93. UserTable * Server::_user = NULL;
    94. }

    makefile:

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

    main.cpp:

    1. #include "data.hpp"
    2. #include "server.hpp"
    3. #define OFFLINE 0
    4. #define ONLINE 1
    5. void DataTest()
    6. {
    7. im_sys::UserTable * _user = new im_sys::UserTable();
    8. //插入用户
    9. // _user->Insert("王五","1111");
    10. //测试用户是否存在
    11. // bool ret = _user->Exists("王五");
    12. // std::cout<
    13. // 判断用户是否在线
    14. // int status = _user->Status("王五");
    15. // if(status ==ONLINE)
    16. // {
    17. // std::cout<<"online!\n";
    18. // }
    19. // else if(status == OFFLINE)
    20. // {
    21. // std::cout<<"offline!\n";
    22. // }
    23. //修改用户状态
    24. _user->UpdateStatus("王五",OFFLINE);
    25. int status = _user->Status("王五");
    26. if(status ==ONLINE)
    27. {
    28. std::cout<<"online!\n";
    29. }
    30. else if(status == OFFLINE)
    31. {
    32. std::cout<<"offline!\n";
    33. }
    34. //检验密码
    35. // bool ret = _user->UserPassCheck("王五","1111");
    36. // if(ret == false)
    37. // {
    38. // std::cout<<"用户名密码错误!\n";
    39. // }
    40. // else
    41. // {
    42. // std::cout<<"login success!\n";
    43. // }
    44. //}
    45. //修改密码
    46. // _user->UpdatePasswd("王五","1111");
    47. // int ret =_user->UserPassCheck("王五","1111");
    48. // if(ret == false)
    49. // {
    50. // std::cout<<"用户名密码错误!\n";
    51. // }
    52. // else
    53. // {
    54. // std::cout<<"login success!\n";
    55. // }
    56. }
    57. void ServerTest()
    58. {
    59. im_sys::Server *server = new im_sys::Server();
    60. server->RunModule();
    61. return;
    62. }
    63. int main()
    64. {
    65. // DataTest();
    66. ServerTest();
    67. return 0;
    68. }

    data.hpp:

    1. #ifndef __M_IM_DATA_H__
    2. #define __M_IM_DATA_H__
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. namespace im_sys{
    9. #define DB_HOST "127.0.0.1"
    10. #define DB_USER "root"
    11. #define DB_PASS "1111"
    12. #define DB_NAME "db_96"
    13. static MYSQL *MysqlInit()
    14. {
    15. MYSQL *mysql = mysql_init(NULL);
    16. if(mysql == NULL)
    17. {
    18. std::cout<<"mysql init failed!\n";
    19. return NULL;
    20. }
    21. if(mysql_real_connect(mysql,DB_HOST,DB_USER,DB_PASS,DB_NAME,0,NULL,0) == NULL)
    22. {
    23. std::cout<<"connect mysql server failed:"<<mysql_error(mysql)<
    24. mysql_close(mysql);
    25. return NULL;
    26. }
    27. if(mysql_set_character_set(mysql,"utf8") != 0)
    28. {
    29. std::cout<<"set mysql client character failed!:"<<mysql_error(mysql)<
    30. mysql_close(mysql);
    31. return NULL;
    32. }
    33. return mysql;
    34. }
    35. static void MysqlDestory(MYSQL *mysql)
    36. {
    37. if(mysql)
    38. {
    39. mysql_close(mysql);
    40. }
    41. return;
    42. }
    43. static bool MysqlQuery(MYSQL *mysql,const std::string &sql)
    44. {
    45. int ret = mysql_query(mysql,sql.c_str());
    46. if(ret != 0)
    47. {
    48. std::cout<
    49. std::cout<<"query failed:"<<mysql_error(mysql)<
    50. return false;
    51. }
    52. return true;
    53. }
    54. class UserTable{
    55. private:
    56. MYSQL *_mysql;
    57. std::mutex _mutex;
    58. public:
    59. UserTable():_mysql(NULL)
    60. {
    61. _mysql = MysqlInit();
    62. if(_mysql == NULL)
    63. {
    64. exit(-1);
    65. }
    66. }
    67. ~UserTable()
    68. {
    69. MysqlDestory(_mysql);
    70. }
    71. bool Insert(const std::string &name,const std::string &pass)
    72. {
    73. #define USER_INSERT "insert im_user values(null,'%s',MD5('%s'),0,now(),now());"
    74. char sql[4096] = {0};
    75. sprintf(sql,USER_INSERT,name.c_str(),pass.c_str());
    76. return MysqlQuery(_mysql,sql);
    77. }
    78. bool Exists(const std::string &name)
    79. {
    80. #define USER_EXISTS "select id from im_user where name='%s';"
    81. char sql[4096] = {0};
    82. sprintf(sql,USER_EXISTS,name.c_str());
    83. bool ret = MysqlQuery(_mysql,sql);
    84. if(ret == false)
    85. {
    86. return false;
    87. }
    88. MYSQL_RES *res = mysql_store_result(_mysql);
    89. int num = mysql_num_rows(res);
    90. if(num!=0)
    91. {
    92. mysql_free_result(res);
    93. return true;
    94. }
    95. mysql_free_result(res);
    96. return false;
    97. }
    98. bool UserPassCheck(const std::string &name,const std::string &pass)
    99. {
    100. #define USER_CHECK "select id from im_user where name='%s' and pass=MD5('%s');"
    101. char sql[4096] = {0};
    102. sprintf(sql,USER_CHECK,name.c_str(),pass.c_str());
    103. bool ret = MysqlQuery(_mysql,sql);
    104. if(ret == false)
    105. {
    106. return false;
    107. }
    108. MYSQL_RES *res = mysql_store_result(_mysql);
    109. int num = mysql_num_rows(res);
    110. if(num!=0)
    111. {
    112. mysql_free_result(res);
    113. return true;
    114. }
    115. mysql_free_result(res);
    116. return false;
    117. }
    118. int Status(const std::string &name)
    119. {
    120. #define USER_STATUS "select status from im_user where name='%s';"
    121. char sql[4096]={0};
    122. sprintf(sql,USER_STATUS,name.c_str());
    123. bool ret = MysqlQuery(_mysql,sql);
    124. if(ret == false)
    125. {
    126. return false;
    127. }
    128. MYSQL_RES *res = mysql_store_result(_mysql);
    129. int num = mysql_num_rows(res);
    130. if(num == 0)
    131. {
    132. mysql_free_result(res);
    133. return -1;
    134. }
    135. MYSQL_ROW row = mysql_fetch_row(res);
    136. int status = std::stoi(row[0]);
    137. mysql_free_result(res);
    138. return status;
    139. }
    140. bool UpdateStatus(const std::string &name,int status)
    141. {
    142. #define USER_UPDATE_STATUS "update im_user set status=%d,stime=now() where name='%s';"
    143. char sql[4096] = {0};
    144. sprintf(sql,USER_UPDATE_STATUS,status,name.c_str());
    145. return MysqlQuery(_mysql,sql);
    146. }
    147. bool UpdatePasswd(const std::string &name,const std::string &pass)
    148. {
    149. #define USER_UPDATE_PASS "update im_user set pass=MD5('%s') where name='%s';"
    150. char sql[4096] = {0};
    151. sprintf(sql,USER_UPDATE_PASS,pass.c_str(),name.c_str());
    152. return MysqlQuery(_mysql,sql);
    153. }
    154. };
    155. }
    156. #endif

    结果如下:

    5.用postman测试用户登录成功后跳转页面 ---302

    server.hpp:

    1. #include "data.hpp"
    2. #include "mongoose.h"
    3. #include "util.hpp"
    4. #include
    5. #include
    6. namespace im_sys{
    7. #define SERVER_PORT 20000
    8. #define OFFLINE 0
    9. #define ONLINE 1
    10. #define WWWROOT "./wwwroot/"
    11. struct IMSession
    12. {
    13. int status;
    14. std::string session_id;//系统时间
    15. std::string username;
    16. time_t ctime;//会话创建时间
    17. time_t ltime;//最后操作时间
    18. struct mg_connection *conn;//当前用户对一个的mongoose连接
    19. };
    20. class Server
    21. {
    22. private:
    23. static struct mg_mgr *_mgr;
    24. static UserTable *_user;
    25. static std::unordered_map _session;
    26. private:
    27. static std::string ConResp(bool res,const std::string &info)
    28. {
    29. Json::Value err;
    30. err["result"] = res;
    31. err["reason"] = info;
    32. std::string body;
    33. JsonUtil::Serialize(err,&body);
    34. return body;
    35. }
    36. static std::string CreateIMSession(struct mg_connection *c,const std::string &username)
    37. {
    38. struct IMSession s;
    39. s.conn = c;
    40. s.username = username;
    41. s.status = ONLINE;
    42. s.ctime = time(NULL);
    43. s.ltime = time(NULL);
    44. s.session_id = std::to_string(time(NULL));
    45. _session[s.session_id] = s;
    46. return s.session_id;
    47. }
    48. static void Login(struct mg_connection *c,struct mg_http_message *hm)
    49. {
    50. //拿到请求正文,进行json反序列化得到用户名和密码
    51. Json::Value user_info;
    52. JsonUtil::UnSerialize(hm->body.ptr,&user_info);
    53. std::string username = user_info["username"].asString();
    54. std::string password = user_info["password"].asString();
    55. //在数据库中验证用户名和密码
    56. bool ret = _user->UserPassCheck(username,password);
    57. if(ret == false)
    58. {
    59. std::string body = ConResp(false,"用户名密码错误");
    60. std::string header = "Content-Type: application/json\r\n";
    61. mg_http_reply(c,400,header.c_str(),body.c_str());
    62. return;
    63. }
    64. //判断用户是否已经在线,若已经在线,则不能重复登录
    65. ret = _user->Status(username);
    66. if(ret == ONLINE)
    67. {
    68. std::string body = ConResp(false,"用户已登录");
    69. std::string header = "Content-Type: application/json\r\n";
    70. mg_http_reply(c,400,header.c_str(),body.c_str());
    71. return;
    72. }
    73. //没在线,则修改用户为在线状态,并且返回登录成功,设置SetCookie包括用户名、用户状态
    74. std::string ssid = CreateIMSession(c,username);
    75. ret = _user->UpdateStatus(username,ONLINE);
    76. if(ret == false)
    77. {
    78. std::string body = ConResp(false,"修改用户状态失败");
    79. std::string header = "Content-Type: application/json\r\n";
    80. mg_http_reply(c,500,header.c_str(),body.c_str());
    81. return;
    82. }
    83. //登录成功需要让客户端去请求一个聊天页面
    84. std::stringstream headers;
    85. headers<< "Location: /chat.html\r\n";
    86. headers <<"Set-Cookie: SSID=" <";Path=/\r\n";
    87. std::string body = ConResp(true,"登录成功");
    88. mg_http_reply(c,302,headers.str().c_str(),body.c_str());
    89. return;
    90. }
    91. static void Register(struct mg_connection *c,struct mg_http_message *hm)
    92. {
    93. //拿到请求信息的正文,是json格式的用户信息,进行解析
    94. Json::Value user_info;
    95. JsonUtil::UnSerialize(hm->body.ptr,&user_info);
    96. std::string username = user_info["username"].asString();
    97. std::string password = user_info["password"].asString();
    98. //在数据库中进行查看用户名是否已经被占用
    99. bool ret = _user->Exists(username);
    100. if(ret == true)
    101. {
    102. Json::Value err;
    103. err["result"] = false;
    104. err["reason"] = "用户名已经被占用";
    105. std::string body;
    106. JsonUtil::Serialize(err,&body);
    107. std::string header = "Content-Type:application/json\r\n";
    108. mg_http_reply(c,400,header.c_str(),body.c_str());
    109. return;
    110. }
    111. //返回结果--注册成功或失败
    112. ret = _user->Insert(username,password);
    113. if(ret == false)
    114. {
    115. Json::Value err;
    116. err["result"] = false;
    117. err["reason"] = "用户插入数据库失败!";
    118. std::string body;
    119. JsonUtil::Serialize(err,&body);
    120. std::string header = "Content-Type: application/json\r\n";
    121. mg_http_reply(c,200,header.c_str(),body.c_str());
    122. return;
    123. }
    124. Json::Value err;
    125. err["result"] = true;
    126. err["reason"] = "注册成功!";
    127. std::string body;
    128. JsonUtil::Serialize(err,&body);
    129. std::string header = "Content-Type:application/json\r\n";
    130. mg_http_reply(c,200,header.c_str(),body.c_str());
    131. return;
    132. }
    133. static bool GetSession(struct mg_connection *c,IMSession *session)
    134. {
    135. auto it = _session.begin();
    136. for(;it!=_session.end();++it)
    137. {
    138. if(it->second.conn == c)
    139. {
    140. *session = it->second;
    141. return true;
    142. }
    143. }
    144. return false;
    145. }
    146. static bool DelSession(IMSession &session)
    147. {
    148. auto it = _session.find(session.session_id);
    149. if(it == _session.end())
    150. {
    151. std::cout<<"not find session\n";
    152. return false;
    153. }
    154. _session.erase(it);
    155. return true;
    156. }
    157. static void ConnClose(struct mg_connection *c)
    158. {
    159. //找到连接对应的session
    160. IMSession session;
    161. bool ret = GetSession(c,&session);
    162. if(ret == false)
    163. {
    164. std::cout<<"have no session info!\n";
    165. return;
    166. }
    167. //修改数据库中的用户状态
    168. ret = _user->UpdateStatus(session.username,OFFLINE);
    169. if(ret == false)
    170. {
    171. std::cout<<"update status offline failed!\n";
    172. return;
    173. }
    174. //删除会话信息
    175. DelSession(session);
    176. }
    177. static void callback(struct mg_connection *c,int ev,void *ev_data,void *fn_data)
    178. {
    179. if(ev == MG_EV_HTTP_MSG)
    180. {
    181. struct mg_http_message *hm = (struct mg_http_message *)ev_data;
    182. if(mg_http_match_uri(hm,"/register"))
    183. {
    184. // mg_http_reply(c,200,"","register success!");
    185. // return;
    186. Register(c,hm);
    187. }
    188. else if(mg_http_match_uri(hm,"/login"))
    189. {
    190. //登录请求
    191. Login(c,hm);
    192. }
    193. else if(mg_http_match_uri(hm,"/cws"))
    194. {
    195. //协议切换请求
    196. }
    197. else
    198. {
    199. //静态页面请求
    200. struct mg_http_serve_opts opts = {.root_dir = WWWROOT};
    201. mg_http_serve_dir(c,hm,&opts);
    202. }
    203. }
    204. else if(ev == MG_EV_WS_OPEN)
    205. {
    206. //websocket握手成功
    207. }
    208. else if(ev == MG_EV_WS_MSG)
    209. {
    210. //收到聊天消息
    211. }
    212. else if(ev == MG_EV_CLOSE)
    213. {
    214. //表示连接断开
    215. ConnClose(c);
    216. }
    217. }
    218. public:
    219. Server()
    220. {
    221. _mgr = new struct mg_mgr();
    222. _user = new UserTable();
    223. }
    224. ~Server()
    225. {
    226. mg_mgr_free(_mgr);
    227. delete _mgr;
    228. delete _user;
    229. }
    230. bool RunModule(int port = SERVER_PORT)
    231. {
    232. std::string addr = "0.0.0.0:";
    233. addr += std::to_string(port);
    234. auto res = mg_http_listen(_mgr,addr.c_str(),callback,_mgr);
    235. if(res ==NULL)
    236. {
    237. std::cout<<"init http listen failed!\n";
    238. return false;
    239. }
    240. while(1)
    241. {
    242. mg_mgr_poll(_mgr,1000);
    243. }
    244. return true;
    245. }
    246. };
    247. struct mg_mgr *Server::_mgr = NULL;
    248. UserTable * Server::_user = NULL;
    249. std::unordered_mapServer::_session;
    250. }

     makefile:

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

    结果如下:

     6.项目网页聊天室总结

    环境搭建:

     1)ubuntu安装mysql    

    https://blog.csdn.net/weixin_42209572/article/details/98983741https://blog.csdn.net/weixin_42209572/article/details/98983741

    2)ubuntu安装mongoose http库   

    链接:https://pan.baidu.com/s/1kMaSz5rduAr5Cs0a88LhrQ  提取码:1111 

          ---主要用到了mongoose.cmongoose.h两个文件

    3)ubuntu安装jsoncpp库 

    (65条消息) Ubuntu16.04 jsoncpp 的安装_只此冒泡君的博客-CSDN博客_ubuntu安装jsoncpphttps://blog.csdn.net/qing310820/article/details/84283650

    4)打开VM虚拟机,通过ifconfig获取主机名,在项目chat.html中修改ws_init方法中的主机名,端口号不用修改。

    结果:

    登录三个会话进行聊天,测试结果如下:

  • 相关阅读:
    Error response from daemon
    设计模式-创建型模式-单例模式
    list容器(20221117)
    【路由优化】基于matlab随机搜索算法优化带有速度的路由网络【含Matlab源码 2046期】
    模拟字符串函数
    对数组进行扩容
    C++中编写没有参数和返回值的函数
    四种强大且隐秘的缓存
    【SpringBoot】配置文件分类
    CDN许可证申请
  • 原文地址:https://blog.csdn.net/weixin_46153828/article/details/126340661