boost 异步服务器开发

目录

1、 异步服务器简介

2、异步服务器开发

2.1 会话类

2.1.1 会话类头文件

2.1.2 会话类源文件

2.2 服务类

2.2.1 服务类头文件

2.2.2 服务类源文件

2.3 主函数

3、异步服务器测试

4、当前异步服务器存在的问题及后续优化


1、 异步服务器简介

        boost 异步服务器分为会话类、服务类, 会话类主要负责与客户端通信, 服务类用来接收客户端连接。

2、异步服务器开发

2.1 会话类

2.1.1 会话类头文件

/**
 * @file session.h
 * @author wangdong ([email protected])
 * @brief 异步服务器开发 会话类
 * @version 0.1
 * @date 2023-06-20
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __SESSION_H__
#define __SESSION_H__

#include "boost/asio.hpp"
#include 
#include 
#include "boost/uuid/random_generator.hpp"
#include "boost/uuid/uuid_io.hpp"

using boost::asio::ip::tcp;

class CServer;

class CSession
{
public:
    CSession(boost::asio::io_context &ioc, CServer *pServer);

    /**
     * @brief Get the Socket object
     *
     * @return tcp::socket&
     */
    tcp::socket &GetSocket() { return m_socket; }

    /**
     * @brief 开始接收客户端消息
     *
     */
    void Start();

    /**
     * @brief Get the Uuid object
     *
     * @return std::string  会话类唯一ID
     */
    std::string GetUuid() { return m_strUuid; }

private:
    /**
     * @brief 处理读回调
     *
     * @param ec 读回调故障码
     * @param bytes 读取字节
     */
    void HandleRead(const boost::system::error_code &ec, size_t bytes);

    /**
     * @brief 处理写回调
     *
     * @param ec 写回调故障码
     */
    void HandleWrite(const boost::system::error_code &ec);

private:
    // 创建通信socket
    tcp::socket m_socket;
    // 创建服务器指针
    CServer *m_pServer;
    // 会话类唯一ID
    std::string m_strUuid;

    enum
    {
        MAX_BUFFER_SIZE = 1024,
    };

    // 读缓冲区
    char m_arrBuffer[MAX_BUFFER_SIZE];
};

#endif /* __SESSION_H__ */

2.1.2 会话类源文件

#include "session.h"
#include "server.h"

CSession::CSession(boost::asio::io_context &ioc, CServer *pServer)
    : m_socket(ioc), m_pServer(pServer)
{
    // 生成唯一ID, 也可以自己实现雪花算法
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    m_strUuid = boost::uuids::to_string(uuid);

    // 初始化读缓冲区
    memset(m_arrBuffer, 0, MAX_BUFFER_SIZE);
}

void CSession::Start()
{
    m_socket.async_read_some(
        boost::asio::buffer(m_arrBuffer, MAX_BUFFER_SIZE),
        std::bind(&CSession::HandleRead, this, std::placeholders::_1, std::placeholders::_2));
}

void CSession::CSession::HandleRead(const boost::system::error_code &ec, size_t bytes)
{
    if (!ec)
    {
        std::cout << "recv:" << m_socket.remote_endpoint().address().to_string() << ":" << m_arrBuffer << std::endl;

        m_socket.async_write_some(boost::asio::buffer(m_arrBuffer, bytes),
                                  std::bind(&CSession::HandleWrite, this, std::placeholders::_1));
    }
    else
    {
        std::cout << "error: " << ec.message() << std::endl;

        m_pServer->ClearSession(m_strUuid);
    }
}

void CSession::HandleWrite(const boost::system::error_code &ec)
{
    if (!ec)
    {
        m_socket.async_read_some(
            boost::asio::buffer(m_arrBuffer, MAX_BUFFER_SIZE),
            std::bind(&CSession::HandleRead, this, std::placeholders::_1, std::placeholders::_2));

        // 初始化读缓冲区
        memset(m_arrBuffer, 0, MAX_BUFFER_SIZE);
    }
    else
    {
        std::cout << "error: " << ec.message() << std::endl;

        m_pServer->ClearSession(m_strUuid);
    }
}

2.2 服务类

2.2.1 服务类头文件

/**
 * @file server.h
 * @author wangdong ([email protected])
 * @brief 服务器开发
 * @version 0.1
 * @date 2023-06-20
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __SERVER_H__
#define __SERVER_H__

#include "session.h"
#include 

class CServer
{
public:
    CServer(boost::asio::io_context &ioc, unsigned short usPort);

    /**
     * @brief 清理会话类对象
     *
     * @param strUuid
     */
    void ClearSession(const std::string &strUuid);

private:
    /**
     * @brief 开始接收客户端连接
     *
     */
    void StartAccept();

    /**
     * @brief 处理接收到服务器处理
     *
     * @param pSession 会话类指针
     * @param ec 故障码
     */
    void HandleAccept(std::shared_ptr pSession, const boost::system::error_code &ec);

private:
    // io上下文
    boost::asio::io_context &m_ioc;
    // tcp接收器
    tcp::acceptor m_acceptor;
    // 会话管理器
    std::map> m_mapSessions;
};

#endif /* __SERVER_H__ */

2.2.2 服务类源文件

#include "server.h"

CServer::CServer(boost::asio::io_context &ioc, unsigned short usPort)
    : m_ioc(ioc), m_acceptor(ioc, tcp::endpoint(tcp::v4(), usPort))
{
    StartAccept();
}

void CServer::ClearSession(const std::string &strUuid)
{
    m_mapSessions.erase(strUuid);
}

void CServer::StartAccept()
{
    // 创建会话类
    std::shared_ptr pSession = std::make_shared(m_ioc, this);

    m_acceptor.async_accept(pSession->GetSocket(), std::bind(&CServer::HandleAccept,
                                                             this, pSession, std::placeholders::_1));
}

void CServer::HandleAccept(std::shared_ptr pSession,
                           const boost::system::error_code &ec)
{
    if (!ec)
    {
        pSession->Start();
        m_mapSessions.insert(std::make_pair(pSession->GetUuid(), pSession));
    }
    else
    {
        std::cerr << "Exception: " << ec.message() << std::endl;
    }

    // 再次等待接收
    StartAccept();
}

2.3 主函数

/**
 * @file main.cpp
 * @author wangdong ([email protected])
 * @brief 异步服务器开发 程序入口
 * @version 0.1
 * @date 2023-06-20
 *
 * @copyright Copyright (c) 2023
 *
 */
#include "server.h"

int main(int argc, char *argv[])
{
    try
    {
        // 创建IO上下文
        boost::asio::io_context ioc;

        // 创建服务器
        CServer server(ioc, 10086);

        // 处理事件循环并阻塞主线程
        ioc.run();
    }
    catch (const std::exception &e)
    {
        std::cerr << "Exception: " << e.what() << '\n';
    }

    return 0;
}

3、异步服务器测试

boost 异步服务器开发_第1张图片

4、当前异步服务器存在的问题及后续优化

当前服务器存在的问题:

1) 当前服务器无法主动发送消息,知道靠收到客户端消息的回调函数来发送消息,现实中不实用。

2) 当前服务器未实现伪闭包延长CSession的生命周期,有可能写回调释放了CSession类后,读回调还会调用。

3)当前服务器未实现粘包、粘包的处理。

综上会在后续博客中优化。

你可能感兴趣的:(服务器,c++,tcp/ip)