验证包含outboundData
并outboundHeader
超过async_write
操作的对象的寿命。
这是在关联的server.cpp示例中完成的,connection
通过 a进行管理shared_ptr
,并将 绑定shared_ptr
到处理程序。以下是代码的相关摘录:
/// Constructor opens the acceptor and starts waiting for the first incoming
/// connection.
server(...)
: acceptor_(...)
{
// Start an accept operation for a new connection.
connection_ptr new_conn(new connection(acceptor_.get_io_service()));
acceptor_.async_accept(new_conn->socket(),
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error, new_conn));
}
/// Handle completion of a accept operation.
void handle_accept(const boost::system::error_code& e, connection_ptr conn)
{
if (!e)
{
// Successfully accepted a new connection. Send the list of stocks to the
// client. The connection::async_write() function will automatically
// serialize the data structure for us.
conn->async_write(...,
boost::bind(&server::handle_write, this,
boost::asio::placeholders::error, conn));
}
...
}
/// Handle completion of a write operation.
void handle_write(const boost::system::error_code& e, connection_ptr conn)
{
// Nothing to do. The socket will be closed automatically when the last
// reference to the connection object goes away.
}
connection
包含outboundData
and的由构造函数中outboundHeader
的 a 创建和管理。然后将 绑定到的处理程序。在 内,连接绑定到的处理程序。尽管什么都不做,但它在链中是至关重要的,因为它通过绑定参数使对象保持活动状态。shared_ptr
server
shared_ptr
server::handle_accept()
async_accept
server::handle_accept()
server::handle_write()
connection::async_write()
server::handle_write()
connection
有人可能会争辩说,如果connection
保证其寿命将超过async_write
操作而不对调用者强加要求,则它的侵入性较小。一个常见的惯用解决方案是connection
继承自enable_shared_from_this
. 当一个类继承自 时enable_shared_from_this
,它提供一个返回有效实例的shared_from_this()
成员函数。shared_ptr
this
这是一个基于Boost.Asio序列化server
示例中的和对象的完整示例。connection
#include <string>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
class connection
: public boost::enable_shared_from_this<connection>
{
public:
/// @brief Constructor.
connection(boost::asio::io_service& io_service)
: socket_(io_service)
{
std::cout << "connection(): " << this << std::endl;
}
~connection()
{
std::cout << "~connection(): " << this << std::endl;
}
/// @brief Get the underlying socket. Used for making a connection
/// or for accepting an incoming connection.
boost::asio::ip::tcp::socket& socket()
{
return socket_;
}
/// @brief Asynchronously write data to the connection, invoking
/// handler upon completion or failure.
template <typename Handler>
void async_write(std::string data, Handler handler)
{
// Perform processing on data and copy to member variables.
using std::swap;
swap(data_, data);
// Create a buffer sequence.
boost::array<boost::asio::const_buffer, 1> buffers = {{
boost::asio::buffer(data_)
}};
std::cout << "connection::async_write() " << this << std::endl;
// Write to the socket.
boost::asio::async_write(
socket_,
buffers, // Buffer sequence copied, not the underlying buffers.
boost::bind(&connection::handle_write<Handler>,
shared_from_this(), // Keep connection alive throughout operation.
boost::asio::placeholders::error,
handler));
}
private:
/// @brief Invokes user provided handler. This member function
/// allows for the connection object's lifespan to be
/// extended during the binding process.
template <typename Handler>
void handle_write(const boost::system::error_code& error,
Handler handler)
{
std::cout << "connection::handle_write() " << this << std::endl;
handler(error);
}
private:
boost::asio::ip::tcp::socket socket_;
std::string data_;
};
class server
{
public:
/// @brief Constructor opens an acceptor, waiting for incoming connection.
server(boost::asio::io_service& io_service,
unsigned short port)
: acceptor_(io_service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
{
start_accept();
}
private:
/// @brief Start an accept operation for a new connection.
void start_accept()
{
boost::shared_ptr<connection> new_conn =
boost::make_shared<connection>(
boost::ref(acceptor_.get_io_service()));
acceptor_.async_accept(new_conn->socket(),
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error, new_conn));
}
/// @brief Handle completion of a accept operation.
void handle_accept(const boost::system::error_code& error,
boost::shared_ptr<connection> conn)
{
if (!error)
{
// Successfully accepted a new connection. Write data to it.
conn->async_write("test data",
boost::protect(
boost::bind(&server::handle_write, this,
boost::asio::placeholders::error)));
}
// Start accepting another connection.
start_accept();
}
void handle_write(const boost::system::error_code& error)
{
std::cout << "server::handle_write()" << std::endl;
}
private:
/// The acceptor object used to accept incoming socket connections.
boost::asio::ip::tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
try
{
// Check command line arguments.
if (argc != 2)
{
std::cerr << "Usage: server <port>" << std::endl;
return 1;
}
unsigned short port = boost::lexical_cast<unsigned short>(argv[1]);
boost::asio::io_service io_service;
server server(io_service, port);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
运行程序,并从另一个终端连接会产生以下输出:
connection(): 0x8cac18c
connection::async_write() 0x8cac18c
connection(): 0x8cac1e4
connection::handle_write() 0x8cac18c
server::handle_write()
~connection(): 0x8cac18c
注意connection
对象的生命周期是如何延长到至少是async_write
操作的生命周期。修改后的 API 允许server
不必管理connection
,因为对象将自行管理。请注意,boost::protect
由于嵌套的boost::bind
. 有一些替代方法不会给调用者带来负担,例如将绑定的处理程序打包在一个元组中,就像connection::async_read()
在 Boost.Asio 示例中所做的那样。