2015-12-01 68 views
0

这是我的第一个boost::asio项目,我想出了一个代码结构,它有一个服务器根据连接请求创建几个会话。C++ boost:asio当会话类被删除时服务器类会发生什么

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

这种机制工作正常,但我不明白在超时删除会话后该怎么办。

这里是服务器StartAccept和服务器的HandleAccept功能:

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中,对象被破坏(我已经记录在对象析构函数中)并且整个程序在Coliru中进入 double free or corruption (out): 0x0000000000e6d5c0 *** Aborted (core dumped)(在我的电脑中)或*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00000000020e0140 *** ==

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

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

帮助赞赏。

+1

不要'删除这个;'。只是不。 – UmNyobe

+0

嗡嗡声..不是'HandleRead'会在'boost'里面永远存在吗?在一些'boost'例子中,他们使用'delete this'“自杀”。请记住,我在每个连接请求中都会打开新会话,如果此对象在一段时间内没有被删除,我将在其附近提供相当数量的处理程序... – Mendes

+0

请在评论中链接这些示例。 – UmNyobe

回答

2

工作方式是,您的会话对象由两个共享指针保持活动状态。一个在定时器的处理程序中,另一个在套接字的处理程序中。

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

当您的超时函数结束时,一个共享指针将超出范围(如果您没有重新启动计时器),但是套接字的读取处理程序中的指针仍然存在。

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

共享指针将被删除,因为处理程序(保存其副本)将被删除。

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

编辑:

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

总是喜欢免费功能版本:asio::async_read(...)asio::async_read_until(...)。那么你不需要照顾简短的阅读。

ASIO是一个美丽的图书馆(恕我直言),但文件假定你是一个专家!

+0

花了很多时间在这么简单和合乎逻辑的事情上......这是预期的'shared_ptr'行为,这就是为什么我使用它!感谢您的帮助! – Mendes

+1

学习ASIO就像学习C++一样 - 它需要很长时间才能学会如何去做,而且一旦你做到了,一切都显得很明显,很美。在那之前,这是地狱。 –

+0

我知道了!这是什么让它美丽...希望我们有这样的朋友来帮助... – Mendes

相关问题