C ++ boost:asio删除会话类时服务器类会发生什么

时间:2015-12-01 16:57:42

标签: c++ asynchronous boost boost-asio

这是我的第一个boost::asio项目,我想出了一个代码结构,它有一个服务器可以根据连接请求创建多个会话。

会话有一个超时机制,我控制是否接收来自客户端的消息。如果在一段时间后没有从客户端发送消息,则会话将自行删除,客户端将重新启动连接以发送其数据。 - 这是预期的行为。客户是小型远程单位。

这个机制运行正常,除了我在删除超时会话后我不明白该怎么做。

以下是服务器的服务器StartAcceptHandleAccept功能:

void SocketServer::StartAccept()
{
    std::shared_ptr<SocketSession> session = std::make_shared<SocketSession>(ioService);
    acceptor.listen();
    acceptor.async_accept(session->getSessionSocket(), boost::bind(&SocketServer::HandleAccept, this, session, boost::asio::placeholders::error));
}

void SocketServer::HandleAccept(std::shared_ptr<SocketSession> session, const boost::system::error_code& errorCode)
    {
        if (errorCode)
        {
            std::cout << "Error accepting incoming connection: Error: " << boost::system::system_error(errorCode).what();
        }
        else
        {
            boost::asio::ip::tcp::socket& socket = session->getSessionSocket();
            session->start();
        }

    StartAccept();
}

会话本身具有以下代码:

void SocketSession::start()
{
    readTimeout.expires_from_now(boost::posix_time::seconds(10));
    readTimeout.async_wait(boost::bind(&SocketSession::TimeoutHandler, shared_from_this(), boost::asio::placeholders::error));
    sessionSocket.async_read_some(boost::asio::buffer(readBuffer, MAX_BUFFER_LENGTH), boost::bind(&SocketSession::HandleRead, shared_from_this(), boost::asio::placeholders::bytes_transferred, boost::asio::placeholders::error));
}

void SocketSession::HandleRead(size_t bytesTransferred, const boost::system::error_code& errorCode)
{
    readTimeout.expires_from_now(boost::posix_time::seconds(10));

    if (errorCode)
    {
        ss << "Error reading data from session: Error: " << boost::system::system_error(errorCode).what();
        delete this; <<<------- PROBLEM HERE
    }
    else
    {
        std::string data(readBuffer, bytesTransferred);
        std::cout << "Data read:" << data << std::endl;
        start();
    }
}

当超时被触发并且代码达到delete this时,对象被销毁(我已在对象析构函数中记录)并且整个程序转到  double free or corruption (out): 0x0000000000e6d5c0 *** Aborted (core dumped)(在我的电脑中)或*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00000000020e0140 *** ==在Coliru。

我很困惑这里发生的事情。我是Coliru - link here的完整版代码。

我期望继续运行服务器等待新连接,即使一个或多个会话超时。

帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

这种方式的工作方式是通过两个共享指针使会话对象保持活动状态。一个在计时器的处理程序中,一个在套接字的处理程序中。

您所要做的就是确保两个共享指针超出范围。

当你的超时功能结束时,一个共享指针将超出范围(如果你不重新启动计时器),但套接字读取处理程序中的那个仍将存在。

所以要做的就是在套接字上调用cancel()。这将导致其处理程序使用包含代码boost :: asio :: errc :: operation_aborted的错误代码触发。如果您在读取处理程序中看到此错误,只需退出该函数。

然后将删除共享指针,因为处理程序(包含它的副本)将被删除。

一旦没有shared_ptr让您保持会话活动,它将被删除并且所有资源都将被回收。

编辑:

另外,我注意到你使用了socket :: read_some。这是asio初学者常见的错误(包括我自己!)。

始终更喜欢免费功能版本:asio::async_read(...)asio::async_read_until(...)。然后你不必处理简短的阅读。

ASIO是一个漂亮的图书馆(恕我直言),但文档假定您是专家!