欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > QT聊天项目DAY05

QT聊天项目DAY05

2025/4/24 0:41:24 来源:https://blog.csdn.net/yumianxiaolangju/article/details/147332630  浏览:    关键词:QT聊天项目DAY05

1.Git拉取项目

编译一下,通过了,虽然会出现报错,但是经常写虚幻C++的人应该对此见怪不怪了吧

2. 实现main.cpp

io_context 所有的异步操作(如网络,信号) 都通过它来调度

注册信号处理器,监听系统终止信号

创建服务器对象实时的监听8080端口是否有客户端请求连接,如果有客户端请求连接,将该连接实例化成一个对象的方式来管理连接中的处理,服务器本身继续监听8080端口是否有新的客户端连接

在连接对象中来处理客户端的读事件

一个端口能够支持成千上万个并发连接

#include <iostream>#include "CServer.h"
#include "HttpConnection.h"
#include "LogicSystem.h"int main()
{try {unsigned short port = static_cast<unsigned short>(8080);                            // 指定服务器监听的端口号net::io_context ioc(1);                                                             // 异步操作的引擎,所有事件循环都通过他来操作,单线程boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);                              // 信号处理,用于退出程序// 绑定信号的回调函数signals.async_wait([&ioc](const boost::system::error_code& error, int sognalNumber){if (error)return;ioc.stop();});std::shared_ptr<CServer> server = std::make_shared<CServer> (ioc, port);server->Start();ioc.run();}catch (std::exception& e) {std::cerr << "Exception: " << e.what() << "\n";return EXIT_FAILURE;}
}

3.编译并且测试服务器是否有效

3.1 测试连接是否有效

输入localhost:8080/getTest

3.2 查询出错原因

crtl + T 文本形式搜索

如果当前对象不是通过std::make_shared<CServer>创建的,调用shared_from_this()就会抛出这个异常

将上述代码修改为

发现即便修改了还是没用,就算是不继承std::enable_shared_from_this<HttpConnection>还是会报错,对不起了,我自己来管理指针,将全部的智能指针删除,直接用裸指针,在使用裸指针时要

自己来管理if判断一下,判断是否为空

全局使用别的对象指针的只有这一个地方

4.解析URL

将一个十六进制的字符转换成对应的数字(0~15)

unsigned char HttpConnection::FromHex(unsigned char c)
{unsigned char y;if(c >= 'A' && c <= 'Z')y = c - 'A' + 10;else if(c >= 'a' && c <= 'z')y = c - 'a' + 10;elsey = c - '0';return y;
}

把一个数字(0~15)转换为它对应的十六进制字符

unsigned char HttpConnection::ToHex(unsigned char c)
{return c > 9 ? c + 55 : c + 48;
}

将输入字符串转换成URL安全的格式

string HttpConnection::UrlEncode(const string& str)
{string strTemp = "";size_t len = str.length();for (size_t i = 0; i < len; i++){if (isalnum((unsigned char)str[i])|| str[i] == '-'|| str[i] == '_'|| str[i] == '.'|| str[i] == '~'){strTemp += str[i];}else{strTemp += '%';strTemp += ToHex((unsigned char)str[i] >> 4);strTemp += ToHex((unsigned char)str[i] & 0x0F);}}return strTemp;
}

将URL转换成字符串

string HttpConnection::UrlDecode(const string& str)
{std::string strTemp = "";size_t length = str.length();for (size_t i = 0; i < length; i++){//还原+为空if (str[i] == '+') strTemp += ' ';//遇到%将后面的两个字符从16进制转为char再拼接else if (str[i] == '%'){assert(i + 2 < length);unsigned char high = FromHex((unsigned char)str[++i]);unsigned char low = FromHex((unsigned char)str[++i]);strTemp += high * 16 + low;}else strTemp += str[i];}return strTemp;
}

将URL参数解析成map,方便后面直接用键取值

/* 将URL参数解析成map,方便后面直接用键取值 */
void HttpConnection::PreParseGetParam()
{// 提取 URI  auto uri = _request.target();// 查找查询字符串的开始位置(即 '?' 的位置)  auto query_pos = uri.find('?');if (query_pos == std::string::npos) {_getUrl = uri;return;}_getUrl = uri.substr(0, query_pos);std::string query_string = uri.substr(query_pos + 1);std::string key;std::string value;size_t pos = 0;while ((pos = query_string.find('&')) != std::string::npos) {auto pair = query_string.substr(0, pos);size_t eq_pos = pair.find('=');if (eq_pos != std::string::npos) {key = UrlDecode(pair.substr(0, eq_pos)); // 假设有 url_decode 函数来处理URL解码  value = UrlDecode(pair.substr(eq_pos + 1));_getParams[key] = value;}query_string.erase(0, pos + 1);}// 处理最后一个参数对(如果没有 & 分隔符)  if (!query_string.empty()) {size_t eq_pos = query_string.find('=');if (eq_pos != std::string::npos) {key = UrlDecode(query_string.substr(0, eq_pos));value = UrlDecode(query_string.substr(eq_pos + 1));_getParams[key] = value;}}
}

这些东西根本记不住,也没必要,问一下AI就行了,毕竟这种接口给它当成原子操作用就完事了

5.处理请求时解析URL

5.1 找到处理连接客户端请求的函数

看这个数据是什么时候获取的,应该是当检测到数据到来时会自动的将数据存储到_request中

所以如果URL是get请求就解析他

/* 处理客户端的请求数据 */
void HttpConnection::HandleRequest()
{_response.version(_request.version());_response.keep_alive(false);													// 处理完该请求后断开连接if (_request.method() == http::verb::get)										// 如果是Http的Get请求{PreParseGetParam();															// 解析客户端发来的URL请求bool IsSucceed = LogicSystem::GetInstance()->HandleGet(_getUrl, this);if (!IsSucceed){_response.result(http::status::not_found);_response.set(http::field::content_type, "text/plain");beast::ostream(_response.body()) << "url not found\r\n";WriteResponse();return;}_response.result(http::status::ok);_response.set(http::field::server, "GateServer");WriteResponse();return;}
}

将解析出来的数据返回出去

LogicSystem::LogicSystem()
{RegisterGet("/getTest", [](HttpConnection* connection){if (connection){beast::ostream(connection->_response.body()) << "receive getTest request";	// 向 Http响应体中写入内容for (auto content : connection->_getParams){beast::ostream(connection->_response.body()) << content.first << " : " << content.second << std::endl;	// 向 Http响应体中写入内容}}else{std::cout << "connection is null" << std::endl;}});
}

6. 注册客户端Post请求

void RegisterPost(std::string, HttpHandler);														// 注册客户端Post请求void LogicSystem::RegisterPost(std::string url, HttpHandler handler)
{_postHandlers[url] = handler;
}

6.1 添加全局头文件

#ifndef GLOBALHEAD_H
#define GLOBALHEAD_H#include <boost/beast/http.hpp>
#include <boost/beast.hpp>
#include <boost/asio.hpp>#include <memory>#include <iostream>#include "Singletion.h"
#include <functional>
#include <map>
#include <unordered_map>
#include <string>#include <json/json.h>
#include <json/value.h>
#include <json/writer.h>
#include <json/reader.h>namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = boost::asio::ip::tcp;enum ErrorCodes
{SUCCESS = 0,ERROR_JSON = 1001,RPC_FAILED = 1002,ERROR_JSON_KEY_EMAIL_LACK = 1003,
};#endif // GLOBALHEAD_H

6.2 绑定Post请求URL对应的回调函数

在这里需要Json来解析Post请求,首先获取Http请求中的内容,然后用jsonCpp这个第三方库的API去解析这个库,再设置服务器回送响应的内容,设置响应头为json文本,判断有没有解析成功,如果没解析成功向响应中添加没有解析成功的错误。如果解析成功了需要判断这个结果中是否包含有email,如果不包含向响应中添加Eamil确实的错误,最后设置解析成功的响应

	// 注册Post请求URL对应的回调函数RegisterPost("/getVarifycode", [](HttpConnection* connection){if (connection){auto bodyStr = boost::beast::buffers_to_string(connection->_request.body());		// 获取 Http请求体中的内容cout << "receive body is " << bodyStr << endl;connection->_response.set(http::field::content_type, "text/json");					// 设置 Http响应头中的 content-typeJson::Value jsonResonse;															// 响应用的JsonJson::Value jsonResult;																// 请求体解析出来的JsonJson::Reader reader;																// Json解析器bool parseSuccess = reader.parse(bodyStr, jsonResult);								// 将请求体解析为Jsonif (!parseSuccess){cout << "parse json failed" << endl;jsonResonse["error"] = ErrorCodes::ERROR_JSON;									// 设置响应的错误码string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;						// 向 Http响应体中写入错误码内容return;}/* 解析成功了,判断是否有想要的key */if (!jsonResult.isMember("email")){cout << "email not found in json" << endl;jsonResonse["error"] = ErrorCodes::ERROR_JSON_KEY_EMAIL_LACK;string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;return;}auto email = jsonResonse["email"].asString();										// 获取解析出来的Emailcout << "email is " << email << endl;jsonResonse["error"] = 0;jsonResonse["email"] = jsonResult["email"];string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;							// 向 Http响应体中写入Json内容return;}else{std::cout << "connection is null" << std::endl;}});

6.3 处理Post请求的函数

bool HandlePost(std::string, HttpConnection*);														// 处理客户端Post请求
bool LogicSystem::HandlePost(std::string url, HttpConnection* connection)
{if (_postHandlers.find(url) == _postHandlers.end())return false;_postHandlers[url](connection);return true;
}

6.4 在连接处理客户端请求时添加Post的判断

	// 如果是Http的Post请求if (_request.method() == http::verb::post)										{bool IsSucceed = LogicSystem::GetInstance()->HandleGet(_request.target(), this);if (!IsSucceed){_response.result(http::status::not_found);_response.set(http::field::content_type, "text/plain");beast::ostream(_response.body()) << "url not found\r\n";WriteResponse();return;}_response.result(http::status::ok);_response.set(http::field::server, "GateServer");WriteResponse();return;}

7. 编译并测试

7.1 编译

参数不匹配,直接丢给AI,问正确的参数是什么?

更改为下列参数

编译成功

7.2 测试Post请求

下载PostMan,需要魔法哦

1. 创建空白分支

2. 填充要发送的客户端请求

URL没有被发现

离谱嗷,更改一下key为下面这一个

还是报错,又回头看了一下代码,复制的get请求,头晕眼花了忘记改了

将之前更改的Key再改回去,跑通了,上传Gitee

8. 上传Gitee

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词