基于boost的https服务器端实现

  • 需求分析

客户需要管理一批数据(数据采集来的),内网环境下让授权用户在任何计算机都可以访问数据,处理数据,但不让下载(保护数据资产安全)

设计是数据存储到mysql服务器,使用redis加速数据中关键参数的访问,由于对数据的访问速度有要求(需要对数据可视化然后进行处理,不能让用户点一下按钮等半天)

 

什么样的数据呢?类似这样,每100ms采集一次的

 

  • 本期解决的问题

1.建立用户管理服务器,响应客户端的登录请求,使用https返回管理员为其分配的mysql账号和密码,redis账号和密码

2.以控制台交互式菜单的形式,实现管理员创建用户,在mysql和redis为用户创建资源的逻辑

 

  • 技术栈 梳理

boost.asio  网络库

openssl创建自签名证书,实现传输数据的https加密

jsoncpp  json数据解析

hiredis  redis数据库访问接口

MySQL Connector/C++   mysql数据库访问接口

asio多线程模型 AsioIOServicePool  asio并发支持

因为暂时用不到后端服务间过程调用,暂不使用grpc(无状态设计,登录状态写到数据库并和客户端心跳验证,解决重登录问题)

 

  • 好了,废话结束,我们开始抄代码

你问我从哪里超,https://gitbookcpp.llfc.club/大佬的博客写的很清楚,我是超人强,越超我越强,开超

程序入口的,main()

int main(int argc, char* argv[])
{
    try
    {
        创建连接池
            MysqlMgr::GetInstance();
        RedisMgr::GetInstance();
        初始化并读取ini文件
        auto& gCfgMgr = ConfigMgr::Inst();
        std::string gate_port_str = gCfgMgr["GateServer"]["Port"];
        unsigned short gate_port = atoi(gate_port_str.c_str());
        创建io_context上下文并启动
        net::io_context ioc{ 1 };
        boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
        signals.async_wait([&ioc](const boost::system::error_code& error, int signal_number) {
            if (error) {
                return;
            }
            ioc.stop();
        });
        std::make_shared<CServer>(ioc)->Start();
        std::cout << "Gate Server listen on port: " << gate_port << std::endl;
        ioc.run();
        RedisMgr::GetInstance()->Close();
    }
    catch (std::exception const& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

然后是cserver的代码

#pragma once

#include <string>
#include "const.h"
 
class CServer :public std::enable_shared_from_this<CServer>
{
public:
CServer(boost::asio::io_context& ioc);
void Start();
private:
tcp::acceptor  _acceptor;
ssl::context _ctx; // 单个全局的 SSL 上下文
 
};
#include "CServer.h"
#include <iostream>
#include "HttpsConnection.h"
#include "AsioIOServicePool.h"
#include <openssl/ssl.h>
 
CServer::CServer(boost::asio::io_context& ioc) : _ctx(ssl::context::tlsv12),
_acceptor(ioc, tcp::endpoint(tcp::v4(), 443))
{
// 加载证书和私钥
_ctx.use_certificate_chain_file("cert.pem");
_ctx.use_private_key_file("key.pem", ssl::context::pem);
 
// 启用会话缓存和其他选项
_ctx.set_options(ssl::context::default_workarounds |
ssl::context::no_sslv2 |
ssl::context::single_dh_use);
 
// 使用 OpenSSL API 设置会话缓存模式为同时启用客户端和服务器端缓存
SSL_CTX* ctx = _ctx.native_handle();
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
 
// 设置密码套件以优先使用 ECDHE
SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384");
 
// 设置验证模式为单向 TLS(仅验证客户端提供的证书,但不要求提供)
_ctx.set_verify_mode(ssl::verify_none);
}
 
void CServer::Start()
{
auto self = shared_from_this();
auto& io_context = AsioIOServicePool::GetInstance()->GetIOService();
std::shared_ptr<HttpsConnection> new_con = std::make_shared<HttpsConnection>(io_context, _ctx);
_acceptor.async_accept(new_con->GetSocket().lowest_layer(), [self, new_con](beast::error_code ec)
{
try {
//出错则放弃这个连接,继续监听新链接
if (ec)
{
self->Start();
return;
}
// 完成 SSL 握手
new_con->GetSocket().async_handshake(ssl::stream_base::server, [new_con, self](beast::error_code ec) {
if (ec) {
std::cerr << "Handshake failed: " << ec.message() << "\n";
self->Start();
return;
}
// 处理新连接,启动 HttpsConnection 类管理新连接
new_con->Start();
//继续监听
self->Start();
 
});
}
catch (std::exception& exp) {
std::cout << "exception is " << exp.what() << std::endl;
self->Start();
} });
}

其他的大同小异,目前https跑通了,逻辑层还待完善,

补充一下跑https过程遇到的问题:

1.证书问题

https需要公钥和私钥,生成自签名证书时,确保你的证书包含正确的Common Name (CN),在SAN字段中明确列出该IP地址。

就是说,如果你服务器ip地址是192.168.124.7,你使用key.pem创建cert.pem时,一定要指定ip地址

然后,在windows中把证书cert.pem注册进去

感兴趣的我会在后面放我的github链接,再次声明,我是超人强,代码全靠超,尊重原作者,也欢迎大家超我!

 

posted on 2024-12-08 22:50  不败剑坤  阅读(12)  评论(0编辑  收藏  举报

导航