Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::asio::tcp::socket Close and cancel without handlers being called

I'm writing a server with boost's asio library. The server handles many concurrent connections using a collection of Connection objects (a wrapper class around boost::asio::tcp::socket). Within the Connection class, the socket is constantly being read from using socket.async_read_some(...) and whenever the read handler is invoked with new data, socket.async_read_some() is immediately called again for more data to be read.

Now, the server may decide to disconnect a client for some reason, so the natural thing to do is to call connection.close() which in turn calls socket.close(), which will cause all pending async operation to be canceled. This causes the read handler (bound to a method within class Connection) to be invoked with boost::asio::error::operation_aborted. And my problem is: I don't want this to happen.

After socket.close(), I'd like to destroy the socket and the connection and then remove its pointer from the server's list of active clients. However the read handler won't be called until the next iteration of io_service.run(), which means that I cannot immediately destroy the socket or the read handler I had passed to socket.async_read_some() until the handler has been invoked with the error. So I have to delay the destruction of those objects somehow; that's annoying.

Is there a safe way to either

  • Cancel pending async operations without any handler to be invoked, so I can safely destroy the socket immediately after socket.close(), or
  • to safely know when no more handlers can potentially be called

Or am I approaching this entirely the wrong way?

like image 203
jlh Avatar asked May 16 '12 22:05

jlh


1 Answers

When an async.operation is complete - either successfuly or with error - its completion handler is invoked. This is important guarantee, and I don't think it's good idea to try and "hack" this behavior. The problem you encountered in your use-case is usually sovled by using shared_ptr (shared_from_this idiom): bind shared_ptr<Connection> to the handlers, don't issue another async_read when you get operation_aborted (or some other error), so that when all the handlers are done the Connection object is destroyed with its socket.

like image 142
Igor R. Avatar answered Sep 29 '22 03:09

Igor R.