You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Boost Asio服务器中Session连接终止与vector存储移除问题

问题描述
  • 在read函数中处理无数据接收的情况,终止连接并通知服务器
  • Session完成数据接收后,从Server类的std::vector<std::shared_ptr<Session>> m_StorageSession中移除对应的Session实例,要求Session通知服务器后由服务器执行移除操作
现有相关代码

Server类代码

void Server::startAcceptNewConnectionAsync()
{
    m_Acceptor.async_accept(
        [this](boost::system::error_code aError_code, boost::asio::ip::tcp::socket aSocket)
        {
            if (!aError_code)
            {
                
                boost::asio::ip::tcp::endpoint endpoint = aSocket.remote_endpoint();

                std::shared_ptr<SessionEchoBoost> newSession = std::make_shared<SessionEchoBoost>
                    (this, m_SessionID.GetFreeID(), endpoint.address().to_string(),
                        endpoint.port(), std::move(aSocket));
                newSession->start();
                
                m_StorageSession.push_back(newSession);
            }
            startAcceptNewConnectionAsync();
        });
}

void Server::notificationAbautCloseConnectionSession(const size_t& theIdSession)
{
    for (int i = 0; i < m_StorageSession.size(); ++i)
    {
        if (m_StorageSession[i]->getIdSession() == theIdSession)
        {
            m_SessionID.DeleteSession(m_StorageSession[i]->getIdSession());
            m_StorageSession[i]->close();
            break;
        }
    }
}

Session类代码

Session::~Session()
{
    if (m_Owner)
    {
        m_Owner->notificationAbautCloseConnectionSession(m_IdSession); // Server*m_Owner 
    }
}

void Session::do_read()
{
    auto self(shared_from_this());
    m_Socket.async_read_some(boost::asio::buffer(m_FrameCommunicationDataIn.getBuforData() + m_FrameCommunicationDataIn.getIndexSaveDataInBuffor(), m_FrameCommunicationDataIn.getSizeBufforData()),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
            if (!ec)
            {
                if (length != 0)
                {
                    m_FrameCommunicationDataIn.setAmauntCopyDataIn(length);
                    newDataFromSession();
                   
                }
                else
                {
                   
                this->~Session();    
                }
                do_read();
            }
        });
}
解决方案

问题1:处理read无数据/连接终止的情况

现有do_read存在两个严重问题:手动调用析构函数会导致内存双重释放,且未处理asio错误码、未终止读取循环。修改后的实现如下:

void Session::do_read()
{
    auto self(shared_from_this());
    m_Socket.async_read_some(
        boost::asio::buffer(
            m_FrameCommunicationDataIn.getBuforData() + m_FrameCommunicationDataIn.getIndexSaveDataInBuffor(),
            m_FrameCommunicationDataIn.getSizeBufforData()
        ),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
            // 处理连接错误或主动关闭的情况
            if (ec)
            {
                close();
                return;
            }

            if (length > 0)
            {
                m_FrameCommunicationDataIn.setAmauntCopyDataIn(length);
                newDataFromSession();
                do_read(); // 继续读取下一批数据
            }
            else
            {
                // 无数据读取,视为连接终止
                close();
            }
        }
    );
}

// 补充Session::close实现
void Session::close()
{
    if (m_Socket.is_open())
    {
        boost::system::error_code ec;
        m_Socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
        m_Socket.close(ec);
    }
}

问题2:从Server的m_StorageSession中移除Session

现有通知函数未完成移除操作,改用erase-remove惯用法处理,避免迭代器失效:

void Server::notificationAbautCloseConnectionSession(const size_t& theIdSession)
{
    auto it = std::remove_if(
        m_StorageSession.begin(),
        m_StorageSession.end(),
        [theIdSession](const std::shared_ptr<Session>& session) {
            return session->getIdSession() == theIdSession;
        }
    );

    if (it != m_StorageSession.end())
    {
        m_SessionID.DeleteSession((*it)->getIdSession());
        (*it)->close();
        m_StorageSession.erase(it, m_StorageSession.end());
    }
}

同时修改Session的通知逻辑,避免依赖析构函数(析构时机不可控),改为在close中主动通知:

void Session::close()
{
    if (m_Socket.is_open())
    {
        boost::system::error_code ec;
        m_Socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
        m_Socket.close(ec);
    }

    if (m_Owner)
    {
        m_Owner->notificationAbautCloseConnectionSession(m_IdSession);
        m_Owner = nullptr; // 防止重复通知
    }
}

// 简化析构函数
Session::~Session()
{
}

内容的提问来源于stack exchange,提问作者zegar zegar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:00:30