这是我的第一个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
时,对象被销毁(我已在对象析构函数中记录)并且整个程序转到
double free or corruption (out): 0x0000000000e6d5c0 ***
Aborted (core dumped)
(在我的电脑中)或*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00000000020e0140 ***
==
在Coliru。
我期望继续运行服务器等待新连接,即使一个或多个会话超时。
帮助表示赞赏。
答案 0 :(得分:2)
这种方式的工作方式是通过两个共享指针使会话对象保持活动状态。一个在计时器的处理程序中,一个在套接字的处理程序中。
您所要做的就是确保两个共享指针超出范围。
当你的超时功能结束时,一个共享指针将超出范围(如果你不重新启动计时器),但套接字读取处理程序中的那个仍将存在。
所以要做的就是在套接字上调用cancel()
。这将导致其处理程序使用包含代码boost :: asio :: errc :: operation_aborted的错误代码触发。如果您在读取处理程序中看到此错误,只需退出该函数。
然后将删除共享指针,因为处理程序(包含它的副本)将被删除。
一旦没有shared_ptr让您保持会话活动,它将被删除并且所有资源都将被回收。
编辑:
另外,我注意到你使用了socket :: read_some。这是asio初学者常见的错误(包括我自己!)。
始终更喜欢免费功能版本:asio::async_read(...)
或asio::async_read_until(...)
。然后你不必处理简短的阅读。
ASIO是一个漂亮的图书馆(恕我直言),但文档假定您是专家!