My Program acts as a server to which a client can connect. Once a client connected, he will get updates from the server every ~5 seconds. This is the write
-function that is called every 5 seconds to send the new data to the client:
void NIUserSession::write(std::string &message_orig)
{
std::cout << "Writing message" << std::endl;
std::shared_ptr<std::string> message = std::make_shared<std::string>( message_orig );
message->append("<EOF>");
boost::system::error_code ec;
boost::asio::async_write(this->socket_, boost::asio::buffer(*message),
boost::asio::transfer_all(), boost::bind(&NIUserSession::writeHandler,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred(),
message
));
}
void NIUserSession::writeHandler(const boost::system::error_code &error, std::size_t bytes_transferred, std::shared_ptr<std::string> message)
{
std::cout << "Write Handler" << std::endl;
if(error)
{
std::cout << "Write handler error: " << error.message() << std::endl;
this->disconnect();
}
}
void NIUserSession::disconnect()
{
std::cout << "Disconnecting client, cancling all write and read operations." << std::endl;
this->socket_.lowest_layer().cancel();
delete this;
}
If there is an error in the write operations the connection between the server and the client gets closed and all async operations are cancled ( this->socket_.lowest_layer().cancel();
).
The problem is that if the connection times out, writeHandler
will not be called immediately. Instead, the write operations "stack up" until the first one reaches writeHandler
.
This should be the normal output of the program:
Writing message
Write Handler
... Other stuff ...
... Other stuff ...
Writing message
Write Handler
If the connections times out, this is what happens:
Writing message
Write Handler
Write handler error: Connection timed out
Disconnecting client, cancling all write and read operations.
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Segmentation fault
At the end, a segmentation fault rises. I think this is because disconnect
is called while other async operations are still on their way. I thought I could avoid it by using this->socket_.lowest_layer().cancel();
directly after the first async operation fails, but it doesn't work.
How can I avoid a segmentation fault?
Well, you should not delete this
when cancelling the operations since the callbacks for the pending I/O operations will still be invoked and then accessing this
leads to undefined behavior. There are multiple ways to tackle this:
std::string
instances passed to NIUserSession::write
in case an outstanding write is still pending and then actually write them in the handler when the outstanding write operation completes. That way you will not have multiple I/O operations in flight. std::enable_shared_from_this
and pass shared_from_this()
instead of this
to the async_write
call (this is what the Boost asynchronous TCP daytime server example does). That way pending I/O operations will keep a reference to your class and the destructor will be called if all of them complete.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.