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
相关产品推荐
相关产品推荐

