boost 异步服务器开发

本文介绍了基于Boost.Asio库构建的异步TCP服务器,包括会话类和服务器类的详细设计。会话类负责与客户端的通信,服务类用于接收和管理客户端连接。代码示例展示了如何处理读写回调以及如何在接收到数据时进行响应。然而,当前服务器存在一些问题,如无法主动发送消息,未处理会话生命周期和粘包问题,这些问题将在后续优化中解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

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 (wangdong1328@163.com)
 * @brief 异步服务器开发 会话类
 * @version 0.1
 * @date 2023-06-20
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __SESSION_H__
#define __SESSION_H__

#include "boost/asio.hpp"
#include <iostream>
#include <memory>
#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 (wangdong1328@163.com)
 * @brief 服务器开发
 * @version 0.1
 * @date 2023-06-20
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __SERVER_H__
#define __SERVER_H__

#include "session.h"
#include <map>

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<CSession> pSession, const boost::system::error_code &ec);

private:
    // io上下文
    boost::asio::io_context &m_ioc;
    // tcp接收器
    tcp::acceptor m_acceptor;
    // 会话管理器
    std::map<std::string, std::shared_ptr<CSession>> 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<CSession> pSession = std::make_shared<CSession>(m_ioc, this);

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

void CServer::HandleAccept(std::shared_ptr<CSession> 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 (wangdong1328@163.com)
 * @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、异步服务器测试

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

当前服务器存在的问题:

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值