1.Websocket
1.1.Websocket的简单认识
WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的消息推送机制。
传统的 web 程序都是属于 "⼀问⼀答" 的形式,即客户端给服务器发送了⼀个 HTTP 请求,服务器 给客⼾端返回⼀个 HTTP 响应。这种情况下服务器是属于被动的一方,在HTTP协议中,如果客⼾端不主动发起请求 ,服务器就⽆法主动给客⼾端响应
像网页即时聊天或者我们做的五子棋游戏这样的程序都是非常依赖 "消息推送" 的, 即需要服务器 主动推动消息到客户端。如果只是使用原生的 HTTP 协议,要想实现消息推送⼀般需要通过 "轮 询" 的方式实现, ⽽轮询的成本⽐较⾼并且也不能及时的获取到消息的响应。
1.2.什么是轮询呢?
比如上图,服务端是无法向主机B主动发送信息,必须让主机B先主动发送信息请求信息到服务端,问服务端有信息了吗,对于主机A也是同样如此,要想获取主机B从服务端发送的信息,服务端是不能主动发送信息到主机A,必须由主机A自己多次申请,这就是“轮询”!
基于上述两个问题, 就产⽣了WebSocket协议。WebSocket 更接近于 TCP 这种级别的通信⽅式,⼀ 旦连接建⽴完成客户端或者服务器都可以主动的向对⽅发送数据。
1.3.websocket协议切换过程
websocketpp协议是由HTTP协议切换过来的,客户端发送协议切换的请求,服务端进行响应,同意切换,这样就变成了websocket的通信连接了
1.4.websocketpp库常用接口认识
1.5.websocketpp库搭建服务器流程
实例化server对象
设置日志输出等级
初始化asio框架种的调度器
设置业务处理回调函数(具体业务处理的函数由我们自己实现)
设置服务器监听端口
开始获取新建连接
启动服务器
1.6.websocketpp库搭建服务器
代码:
#include <iostream>
#include <string>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
typedef websocketpp::server<websocketpp::config::asio> wsserver_t;
void print(const std::string &str)
{
std::cout << str << std::endl;
}
void http_callback(wsserver_t *srv, websocketpp::connection_hdl hdl) {
//给客户端返回一个hello world的页面
wsserver_t::connection_ptr conn = srv->get_con_from_hdl(hdl);
std::cout << "body: " << conn->get_request_body() << std::endl;
websocketpp::http::parser::request req = conn->get_request();
std::cout << "method: " << req.get_method() << std::endl;
std::cout << "uri: " << req.get_uri() << std::endl;
std::string body = "<html><body><h1>Hello World</h1></body></html>";
conn->set_body(body);
conn->append_header("Content-Type", "text/html");
//conn->set_body(conn->get_request_body());
conn->set_status(websocketpp::http::status_code::ok);
//wsserver_t::timer_ptr tp = srv->set_timer(5000, std::bind(print, "bitejiuyeke"));
//tp->cancel();//定时任务的取消,会导致定时任务立即被执行
}
void wsopen_callback(wsserver_t *srv, websocketpp::connection_hdl hdl) {
std::cout << "websocket握手成功!!\n";
}
void wsclose_callback(wsserver_t *srv, websocketpp::connection_hdl hdl) {
std::cout << "websocket连接断开!!\n";
}
void wsmsg_callback(wsserver_t *srv, websocketpp::connection_hdl hdl, wsserver_t::message_ptr msg) {
wsserver_t::connection_ptr conn = srv->get_con_from_hdl(hdl);
std::cout << "wsmsg: " << msg->get_payload() << std::endl;
std::string rsp = "client say: " + msg->get_payload();
conn->send(rsp, websocketpp::frame::opcode::text);
}
int main()
{
//1. 实例化server对象
wsserver_t wssrv;
//2. 设置日志等级
wssrv.set_access_channels(websocketpp::log::alevel::none);
//3. 初始化asio调度器
wssrv.init_asio();
wssrv.set_reuse_addr(true);
//4. 设置回调函数
wssrv.set_http_handler(std::bind(http_callback, &wssrv, std::placeholders::_1));
wssrv.set_open_handler(std::bind(wsopen_callback, &wssrv, std::placeholders::_1));
wssrv.set_close_handler(std::bind(wsclose_callback, &wssrv, std::placeholders::_1));
wssrv.set_message_handler(std::bind(wsmsg_callback, &wssrv, std::placeholders::_1, std::placeholders::_2));
//5. 设置监听端口
wssrv.listen(8085);
//6. 开始获取新连接
wssrv.start_accept();
//7. 启动服务器
wssrv.run();
return 0;
}
AI写代码
cpp
运行
我们想要在页面生成一个Hello World
成功生成!我们使用websocketpp协议搭建网络通信平台成功!
2.mysqlclient库-接口认识
mysql数据库的访问操作流程:
客户端初始化过程:
1.初始化mysql操作句柄
2.连接mysql服务器
3.设置客户端的字符集
4.选择想要操作的数据库
客户端对数据库中数据的操作:
新增,修改,删除,都是只要sql语句执行成功了,数据库中的数据就发生了改变,没有反馈结果
查询是不一样的,因为需要首先执行语句成功,需要将查询结果保存到本地进行访问
5.执行sql语句
一旦成功,如果是增删改,则就完毕了,
查询:
6.将查询结果保存到本地
7.获取查询结果集中的结果条数
8.遍历获取结果集中的每一条数据进行处理
9.释放结果集,避免内存泄露
10.释放MySQL操作句柄
用例代码:
#include <stdio.h>
#include <string.h>
#include <mysql/mysql.h>
#define HOST "127.0.0.1"
#define PORT 3306
#define USER "root"
#define PASS "qwer@wu.888"
#define DBNAME "gobang"
int main()
{
//1. 初始化mysql句柄
// MYSQL *mysql_init(MYSQL *mysql);
MYSQL *mysql = mysql_init(NULL);
if (mysql == NULL) {
printf("mysql init failed!\n");
return -1;
}
//2. 连接服务器
// MYSQL *mysql_real_connect(mysql, host, user, pass, dbname, port, unix_socket, flag);
if (mysql_real_connect(mysql, HOST, USER, PASS, DBNAME, PORT, NULL, 0) == NULL) {
printf("connect mysql server failed : %s\n", mysql_error(mysql));
mysql_close(mysql);
return -1;
}
//3. 设置客户端字符集
// int mysql_set_character_set(mysql, "utf8");
if (mysql_set_character_set(mysql, "utf8") != 0) {
printf("set client character failed : %s\n", mysql_error(mysql));
mysql_close(mysql);
return -1;
}
//4. 选择要操作的数据库
// int mysql_select_db(mysql, dbname)
// mysql_select_db(mysql, DBNAME);
//5. 执行sql语句
// int mysql_query(MYSQL *mysql, char *sql);
//char *sql = "insert stu values(null, '小明', 18, 53, 68, 87);";
//char *sql = "update stu set ch=ch+40 where sn=1;";
//char *sql = "delete from stu where sn=1;";
char *sql = "select * from stu;";
int ret = mysql_query(mysql, sql);
if (ret != 0) {
printf("%s\n", sql);
printf("mysql query failed : %s\n", mysql_error(mysql));
mysql_close(mysql);
return -1;
}
//6. 如果sql语句是查询语句,则需要保存结果到本地
// MYSQL_RES *mysql_store_result(MYSQL *mysql)
MYSQL_RES *res = mysql_store_result(mysql);
if (res == NULL) {
mysql_close(mysql);
return -1;
}
//7. 获取结果集中的结果条数
// int mysql_num_rows(MYSQL_RES *res);
// int mysql_num_fields(MYSQL_RES *res);
int num_row = mysql_num_rows(res);
int num_col = mysql_num_fields(res);
//8. 遍历保存到本地的结果集
for (int i = 0; i < num_row; i++) {
// MYSQL_ROW mysql_fetch_row(MYSQL *res);
MYSQL_ROW row = mysql_fetch_row(res);
for (int i = 0; i < num_col; i++) {
printf("%s\t", row[i]);
}
printf("\n");
}
//9. 释放结果集
mysql_free_result(res);
//10. 关闭连接,释放句柄
mysql_close(mysql);
return 0;
}
AI写代码
cpp
运行
试着插入新数据,查询结果,成功!
3.项目模块的划分:
4.项目流程图:
4.1.玩家用户角度流程图:
4.2.服务器流程结构图:
5.实用的工具模块:
5.1.日志的实现
日志宏的实现的一些前置知识:
代码:
#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#include <stdio.h>
#include <time.h>
#define INF 0
#define DBG 1
#define ERR 2
#define DEFAULT_LOG_LEVEL INF
#define LOG(level, format, ...) do{\
if (DEFAULT_LOG_LEVEL > level) break;\
time_t t = time(NULL);\
struct tm *lt = localtime(&t);\
char buf[32] = {0};\
strftime(buf, 31, "%H:%M:%S", lt);\
fprintf(stdout, "[%s %s:%d] " format "\n", buf, __FILE__, __LINE__, ##__VA_ARGS__);\
}while(0)
#define ILOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
#define DLOG(format, ...) LOG(DBG, format, ##__VA_ARGS__)
#define ELOG(format, ...) LOG(ERR, format, ##__VA_ARGS__)
#endif
AI写代码
cpp
运行
5.2.mysql工具类编译与测试
这个报错是为什么?
因为我们把第一步忘记了,第一步需要创建表结构
添加表结构之后,我们再执行一遍,成功添加小黑的信息!
代码:
class mysql_util {
public:
static MYSQL *mysql_create(const std::string &host,
const std::string &username,
const std::string &password,
const std::string &dbname,
uint16_t port = 3306) {
MYSQL *mysql = mysql_init(NULL);
if (mysql == NULL) {
ELOG("mysql init failed!");
return NULL;
}
//2. 连接服务器
if (mysql_real_connect(mysql,
host.c_str(),
username.c_str(),
password.c_str(),
dbname.c_str(), port, NULL, 0) == NULL) {
ELOG("connect mysql server failed : %s", mysql_error(mysql));
mysql_close(mysql);
return NULL;
}
//3. 设置客户端字符集
if (mysql_set_character_set(mysql, "utf8") != 0) {
ELOG("set client character failed : %s", mysql_error(mysql));
mysql_close(mysql);
return NULL;
}
return mysql;
}
static bool mysql_exec(MYSQL *mysql, const std::string &sql) {
int ret = mysql_query(mysql, sql.c_str());
if (ret != 0) {
ELOG("%s\n", sql.c_str());
ELOG("mysql query failed : %s\n", mysql_error(mysql));
return false;
}
return true;
}
static void mysql_destroy(MYSQL *mysql) {
if (mysql != NULL) {
mysql_close(mysql);
}
return ;
}
};
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。