整理服务器结构

1.前言

前面花了一些时间把需要用到的技术进行了简单的讲解,把需要的环境也做了部署和安装。但是现在只是一个零散的代码,并不是一个整体的项目。后面就要开始正式的去写一个服务器了,所以我们需要把这些零散的东西做一个整理。

2.设计思路

①写一个线程基类,所有的工具都继承于这个线程基类,这样可以通过保存线程基类的指针,完成对所有工具的统一管理。

②把需要异步操作的工具进行封装,使之可以进行异步操作,这些工具包括timer mysql redis socket log等。

③创建一个def.h,用来保存宏定义和一些通用类型的定义。

④设计一个进程基类,把这些工具放在同一个进程。

3.开始整理

这里先分享一下我的代码

链接:https://pan.baidu.com/s/1-RrbPquu_g9Wbnedh2fe2g 
提取码:vqg7 

①在工作目录下创建一个lib目录,一个include目录

②将mysql和protobuf需要用到的动态链接库和头文件分别放在lib和include里面

 

③将Makefile的绝对路径改为相对路径

④将run.sh的绝对路径改为相对路径

 

⑤创建一个 XInclude目录用来保存封装好的工具

⑥创建一个XProcess目录用来保存进程的子类(进程的具体逻辑)

 ⑦我把代码打一个完整的包,大家可以下载下来看看

链接:https://pan.baidu.com/s/1-RrbPquu_g9Wbnedh2fe2g 
提取码:vqg7 

4.代码的思路

①封装一个线程类XThraed.h和XThread.cpp


/**********************************************************                                                                                                                                                        
 * Author        : 谢名聪
 * Email         : 869408604@qq.com
 * Last modified : 2022-04-21 11:43
 * Filename      : XThread.h
 * Description   : 异步线程类
 * *******************************************************/

#ifndef X_THREAD_H
#define X_THREAD_H

#include <atomic>
#include <future>
#include <chrono>

class XThread
{
    public:
        void run();
        void stop();
        bool status();

    private:
        virtual bool exec() = 0;//当状态是false的时候结束线程

    private:
        bool m_status = false;
        std::future<bool> m_future;
};

#endif
#include "XThread.h"                                                                                                                                                                                               

void XThread::run()
{
    m_status = true;
    m_future = std::async(std::launch::async, std::bind(&XThread::exec, this));
}

void XThread::stop()
{
    m_status = false;
}

bool XThread::status()
{
    return m_status;
}

②让mysql继承这个线程,后面可以开发异步mysql操作

/**********************************************************
 * Author        : 谢名聪
 * Email         : 869408604@qq.com
 * Last modified : 2022-04-21 11:45
 * Filename      : XMysql.h
 * Description   : xsqly类,提供同步异步两种操作
 * *******************************************************/

#ifndef X_MYSQL
#define X_MYSQL

#include "../XThread/XThread.h"
#include "mysqlToProtobuf.h"
#include "/usr/local/mysql/include/mysql.h"
#include <iostream>
#include <vector>

struct XMysqlRes
{
    bool suc = false;
    std::vector<std::vector<std::string>> res;
};

class XMysql : public XThread
{
    public:
        bool exec() override {};
    
    public:
        //初始化数据库
        bool init(const char* host, const char* port, const char* user, const char* pwd, const char* db, const uint32_t timeout = 2);
    
    public:
        //有返回的操作
        XMysqlRes exeSqlStore(const char* sql);
        //无返回的操作
        bool exeSql(const char* sql);
        //定义一个模板,针对不同的protobuf结构
        template<typename PROTO_TYPE>
        //这里必须再类内实现,在类外实现的话,进行外部链接的时候会出错
        bool exeSqlProtobuf(const char* sql, std::vector<std::shared_ptr<PROTO_TYPE>>& protoRes)
        {
            if (!exeSql(sql)) {
                std::cout << "XMysql exeSqlStore error! sql=" << sql << std::endl;
                return false;
            }
            //转成protobuf形式
            mysqlToProtobuf(mysql_store_result(&m_mysql), protoRes);
            return true;
        }
        //校验连接状态
        void check();
        //连接数据库
        bool connect();

    private:
        MYSQL m_mysql;
        std::string m_host = "";
        std::string m_user = "";
        std::string m_pwd = "";
        std::string m_db = "";
        uint32_t m_port = 0;
        uint32_t m_timeout = 0;
};

#endif
#include "XMysql.h"

bool XMysql::init(const char* host, const char* port, const char* user, const char* pwd, const char* db, const uint32_t timeout)
{
    m_host = host;
    m_port = std::atoi(port);
    m_user = user;
    m_pwd = pwd;
    m_db = db;
    m_timeout = timeout;

    if (connect()) {
        std::cout << "XMysql connect error" << std::endl;
        return false;
    }

    return true;
}

bool XMysql::exeSql(const char* sql)
{
    if (mysql_real_query(&m_mysql,sql,strlen(sql)) != 0) {
        std::cout << "XMysql exeSql error! sql=" << sql << std::endl;
        return false;
    }
   return true;
}

XMysqlRes XMysql::exeSqlStore(const char* sql)
{
    XMysqlRes res;
    check();
    if (!exeSql(sql)) {
        std::cout << "XMysql exeSqlStore error! sql=" << sql << std::endl;
        return res;
    }
    //执行成功
    res.suc = true;
    //查询结果
    auto result = mysql_store_result(&m_mysql);
    //行数
    auto rowNum = mysql_num_rows(result);
    //列数
    auto fiedNum = mysql_num_fields(result);
    for (int i = 0; i < rowNum; i++) {
        auto row = mysql_fetch_row(result);
        std::vector<std::string> rows;
        for (int j = 0; j < fiedNum; j++) {
            rows.push_back(row[j]);
        }
        res.res.push_back(rows);
    }

    return res;
}

void XMysql::check()
{
    //ping返回0时表示正常
    if (mysql_ping(&m_mysql) != 0) {
        std::cout << "XMysql ping == 0" << std::endl;
        //关闭mysql
        mysql_close(&m_mysql);
        return;
    }
    
    //重新连接
    connect();
}

bool XMysql::connect()
{
    //初始化
    if (!mysql_init(&m_mysql)) {
        std::cout << "XMysql init error!" << std::endl;
        return false;
    }
    //连接数据库
    if (!mysql_real_connect(&m_mysql, m_host.c_str(), m_user.c_str(), m_pwd.c_str(), m_db.c_str(), m_port, NULL, CLIENT_MULTI_STATEMENTS)) {
        std::cout << "XMysql connect error!" << std::endl;
        return false;
    }
    //设置参数
    mysql_options(&m_mysql, MYSQL_OPT_READ_TIMEOUT, &m_timeout);
    mysql_options(&m_mysql, MYSQL_SET_CHARSET_NAME, "utf8");
} 

③封装一个进程类Process

/**********************************************************
 * Author        : 谢名聪
 * Email         : 869408604@qq.com
 * Last modified : 2022-04-21 11:42
 * Filename      : Process.h
 * Description   : 进程的基类
 * *******************************************************/

#ifndef PROCESS_H
#define PROCESS_H

#include "XInclude/XMysql/XMysql.h"
#include "XInclude/XConfig/XConfig.h"

class Process
{
    public:
        Process();
        virtual ~Process();

    //进程子类需要实现的逻辑
    private:
        virtual bool initProcess() = 0;
        virtual bool startProcess() = 0;
        virtual bool stopProcess() = 0;

    //main.cpp中调用的逻辑
    public:
        bool init(const std::string config);
        bool start();
        bool stop();

    //*********************************************************
    //工具类:包括config socket  redis mysql timer log等
    //*********************************************************

    //---------------------------------------------------------
    //config
    //--------------------------------------------------------
    private:
        std::shared_ptr<XConfig> m_config;
    public:
        //获取配置
        std::string getConfigValue(const std::string groupKey, const std::string key);

    //-----------------------------------------------------------
    //同步Mysql
    //-----------------------------------------------------------
    private:
        //同步数据库,只操作一些简单的逻辑
        std::map<uint32_t, std::shared_ptr<XMysql>> m_XMysqls;
    public:
        //增加数据库服务
        bool addMysqlServer(uint32_t id, const char* host, \
                const char* port, const char* user, \
                const char* pwd, const char* db, \
                uint32_t timeout = 2);
        //无返回值
        bool exeSql(uint32_t id, const char* sql); 
        //返回XMysql
        XMysqlRes exeSqlStore(uint32_t id, const char* sql);
        //返回protobuf
        template<typename PROTO_TYPE>
        bool exeSqlProtobuf(uint32_t id, const char* sql, std::vector<std::shared_ptr<PROTO_TYPE>>& protoRes)
        {
            auto it = m_XMysqls.find(id);
            if (it == m_XMysqls.end()) {
                return false;
            }

            return m_XMysqls[id]->exeSqlProtobuf(sql, protoRes);
        } 

    private:
        //异步类型  有一些不需要马上得到结果的操作可以在这完成
        std::map<uint32_t, std::shared_ptr<XMysql>> m_asyncXMysqls;
    public:
        std::string m_name = "";
        uint32_t m_type = 0;
        uint32_t m_id = 0;
};
extern Process* g_process;

#endif
#include "Process.h"

Process* g_process = nullptr;

Process::Process()
{
    if (!g_process) {
        g_process = this; 
    }
    if (!m_config) {
        m_config = std::make_shared<XConfig>();
    }
}

Process::~Process()
{
}

bool Process::init(const std::string config)
{
    try {
        // 加载配置
        if (!m_config->load(config)) {
            std::cout << "load config error" << std::endl;
            return false;
        }
        // 初始化进程
        if (!initProcess()) {
            std::cout << "initProcess error!" << std::endl;;
            return false;
        }

    } catch (std::exception& ex) {
        std::cout << "Process, init ex= " << ex.what() << std::endl;
    }

    std::cout << "Process, init success!" << std::endl;
    return true;
}

bool Process::start()
{
    try {
    // 开启服务逻辑
    if (!startProcess()) {
        std::cout << "startProcess error!" << std::endl;
        return false;
    }

    } catch (std::exception& ex) {
        std::cout << "PROCESS, start ex = " << ex.what() << std::endl;
    }

    std::cout << "PROCESS, start success!" << std::endl;

    return true;
}

bool Process::stop()
{
    try {
        //关闭服务逻辑
        stopProcess();

        std::cout << "PROCESS, " << m_name << "stopped" << std::endl;;

    } catch (std::exception& ex) {
        std::cout << "stop ex, " << ex.what() << std::endl;
    }

    return true;
}

std::string Process::getConfigValue(const std::string groupKey, const std::string key)
{
    return m_config->getConfigValue(groupKey, key);
}

bool Process::addMysqlServer(uint32_t id, const char* host, \
        const char* port, const char* user, \
        const char* pwd, const char* db, \
        uint32_t timeout)
{
    auto it = m_XMysqls.find(id);
    if (it != m_XMysqls.end()) {
        return true;
    }
    auto mysql = std::make_shared<XMysql> ();
    mysql->init(host, port, user, pwd, db, timeout);
    m_XMysqls[id] = mysql;
    return true;
}

bool Process::exeSql(uint32_t id, const char* sql)
{
    auto it = m_XMysqls.find(id);
    if (it == m_XMysqls.end()) {
        return false;
    }

    return m_XMysqls[id]->exeSql(sql);
}


XMysqlRes Process::exeSqlStore(uint32_t id, const char* sql)
{
    auto it = m_XMysqls.find(id);
    if (it == m_XMysqls.end()) {
        return XMysqlRes();
    }

    return m_XMysqls[id]->exeSqlStore(sql);
}

④把main.cpp也改一改

/**********************************************************
 * Author        : 谢名聪
 * Email         : 869408604@qq.com
 * Last modified : 2022-04-21 11:42
 * Filename      : main.cpp
 * Description   : 程序的入口
 * *******************************************************/
#include "Process.h"

#include <iostream>
#include <signal.h>
#include <sys/stat.h>

void sig_handler(int sig)
{
    //接收到信号关闭进程
    g_process->stop();
}

void set_signal_handlers(void)
{
    signal(SIGHUP, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);

    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = sig_handler;
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT, &act, NULL);
}

int main(int argc, char** argv)
{
    //没有传配置文件
    if (argc < 2) {
        std::cout << "need config" << std::endl;
        return -1;
    }

    //没有初始化g_process
    if (g_process == nullptr) {
        std::cout << "g_process == nullptr" << std::endl;
        return -1;
    }

    //加载配置
    if (!g_process->init(argv[1])) {
    std::cout << "g_process init error" << std::endl;
        return -1;
    }

    //当接收到关闭信号,则关闭程序
   set_signal_handlers(); 

   //主进程
   if (!g_process->start()) {
       std::cout << "process error" << std::endl;
       return -1;
   }

   std::cout << "main.cpp stop" << std::endl;
    return 0;
}

⑤写一个XProcess测试一下我们这个框架是否可用

/**********************************************************
 * Author        : 谢名聪
 * Email         : 869408604@qq.com
 * Last modified : 2022-04-21 11:59
 * Filename      : XProcess.h
 * Description   : 进程的子类,需要实现三个纯虚函数
 * *******************************************************/

#ifndef X_PROCESS
#define X_PROCESS
#include "../Process.h"

class XProcess : public Process
{
    private:
        virtual bool initProcess() override;
        virtual bool startProcess() override;
        virtual bool stopProcess() override;
    private:
        bool m_stop = false;
};

extern XProcess xprocess;
#endif
#include "XProcess.h"
#include  <unistd.h>
#include <time.h>
XProcess xprocess;

bool XProcess::initProcess()
{
    //加载数据库
    std::string host = getConfigValue("mysql", "host");
    std::string port = getConfigValue("mysql", "port");
    std::string user = getConfigValue("mysql", "user");
    std::string pwd = getConfigValue("mysql", "pwd");
    std::string db = getConfigValue("mysql", "db");
    std::string sqlType = getConfigValue("mysql", "type");
    uint32_t type = std::atoi(sqlType.c_str());
    if (!addMysqlServer(type, host.c_str(), port.c_str(), user.c_str(), pwd.c_str(), db.c_str())) {
        std::cout << "addMysqlServer error" << std::endl;
        return false;
    }

    //加载服务名字和类型
    std::string serverName = getConfigValue("server", "name");
    std::string serverType = getConfigValue("server", "type");
    std::string serverId = getConfigValue("server", "id");

    m_name = serverName;
    m_type = std::atoi(serverType.c_str());
    m_id = std::atoi(serverId.c_str());

    return true;
}

bool XProcess::startProcess()
{
    while (m_stop == false) {
        //获取系统时间戳
        time_t timeReal;
        time(&timeReal);
        timeReal = timeReal + 8 * 3600;
        tm* t = gmtime(&timeReal); 
        printf("%d-%02d-%02d %02d:%02d:%02d\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); 
        sleep(1);
    };
    return true;
}

bool XProcess::stopProcess()
{
 
    std::cout << "stop  " << m_name << std::endl; 
    m_stop = true;
    return true;
}

 5.测试一下这个结构是否可用

 6.小结

①目前来说,还远远没有达到应用级别,但是基本框架已经非常清晰了。后面我准备把Process基类和main.cpp封装成静态链接库的形式,服务器的开发只在Xprocess上完成。

②现在大多数工具都还没有开始写,后面会陆续的完成mysql,socket,timer,log和redis等工具的封装。

③这个服务器后面肯定还会碰到非常多需要开发和优化的地方,后面希望用博客的形式一点点的记录自己的成长。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值