调用socket.close() 不会破坏套接字。但是,应用程序可能需要管理操作和完成处理程序所依赖的对象的生命周期,但这不一定是套接字对象本身。例如,考虑一个client 类,它拥有一个缓冲区、一个套接字,并且有一个未完成的读取操作,完成处理程序为client::handle_read()。可以close() 并显式销毁套接字,但缓冲区和client 实例必须保持有效,直到至少调用处理程序:
class client
{
...
void read()
{
// Post handler that will start a read operation.
io_service_.post([this]() {
async_read(*socket, boost::asio::buffer(buffer_);
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
});
}
void handle_read(
const boost::system::error_code& error,
std::size_t bytes_transferred
)
{
// make use of data members...if socket_ is not used, then it
// is safe for socket to have already been destroyed.
}
void close()
{
io_service_.post([this]() {
socket_->close();
// As long as outstanding completion handlers do not
// invoke operations on socket_, then socket_ can be
// destroyed.
socket_.release(nullptr);
});
}
private:
boost::asio::io_service& io_service_;
// Not a typical pattern, but used to exemplify that outstanding
// operations on `socket_` are not explicitly dependent on the
// lifetime of `socket_`.
std::unique_ptr<boost::asio::socket> socket_;
std::array<char, 512> buffer_;
...
}
应用程序负责管理操作和处理程序所依赖的对象的生命周期。 chat client example 通过等待 io_service.run() 在线程 join() 中返回,保证 chat_client 实例在其不再使用之后被销毁,从而实现了这一点:
int main(...)
{
try
{
...
boost::asio::io_service io_service;
chat_client c(...);
std::thread t([&io_service](){ io_service.run(); });
...
c.close();
t.join(); // Wait for `io_service.run` to return, guaranteeing
// that `chat_client` is no longer in use.
} // The `chat_client` instance is destroyed.
catch (std::exception& e)
{
...
}
}
管理对象生命周期的一个常见习惯是让 I/O 对象由继承自 enable_shared_from_this<> 的单个类管理。当一个类从enable_shared_from_this 继承时,它提供一个shared_from_this() 成员函数,该函数返回一个有效的shared_ptr 实例来管理this。 shared_ptr 的副本被传递给完成处理程序,例如 lambdas 中的捕获列表或作为实例句柄传递给 bind(),导致 I/O 对象的生命周期至少延长到处理程序。有关使用此方法的示例,请参阅 Boost.Asio asynchronous TCP daytime server 教程。