gpt4 book ai didi

c++ - 为什么 boost::asio::async_write 导致崩溃?

转载 作者:行者123 更新时间:2023-11-28 00:41:47 30 4
gpt4 key购买 nike

我的服务器运行良好,直到客户端连接,然后它尝试向客户端发送消息。这是向客户端发送消息的函数。当此代码运行时,它会因错误而崩溃

SERVER.exe 中 0x6351117C (msvcr110d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000002。

    template <typename T, typename Handler>
void AsyncWrite(const T& t, Handler handler)
{
std::ostringstream archiveStream;
boost::archive::text_oarchive archive(archiveStream);
archive << t;
outboundData = archiveStream.str();

std::ostringstream headerStream;
headerStream << std::setw(headerLength) << std::hex << outboundData.size();
if (!headerStream || headerStream.str().size() != headerLength)
{
boost::system::error_code error(boost::asio::error::invalid_argument);
socket.get_io_service().post(boost::bind(handler, error));
return;
}
outboundHeader = headerStream.str();

std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(outboundHeader));
buffers.push_back(boost::asio::buffer(outboundData));
boost::asio::async_write(socket, buffers, handler);
}

编辑:不知道这是否重要,但我正在关注这个例子

http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/example/cpp03/serialization/connection.hpp

最佳答案

验证包含 outboundDataoutboundHeader 的对象的生命周期是否超过 async_write 操作的生命周期。

这是在相关的 server.cpp 中完成的例如,通过 shared_ptr 管理 connection,并将 shared_ptr 绑定(bind)到处理程序。以下是代码的相关摘录:

/// 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.
}

包含 outboundDataoutboundHeaderconnectionshared_ptr 创建和管理 服务器构造函数。 shared_ptr 然后绑定(bind)到 server::handle_accept()async_accept 的处理程序。在 server::handle_accept() 中,连接绑定(bind)到 server::handle_write()connection::async_write() 的处理程序.尽管 server::handle_write() 什么都不做,但它在链中很关键,因为它通过其绑定(bind)参数使 connection 对象保持事件状态。


有人可能会争辩说,如果 connection 保证其生命周期将超过 async_write 操作而不对调用者强加要求,那么侵入性就会降低。一个常见的惯用解决方案是让 connection 继承自 enable_shared_from_this .当一个类继承自 enable_shared_from_this 时,它提供了一个 shared_from_this() 成员函数,该函数返回一个有效的 shared_ptr 实例给 this.

这是一个基于 Boost.Asio 中的 serverconnection 对象的完整示例 serialization示例。

#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::bindboost::protect 是必需的。有一些替代方法不会给调用者带来负担,例如将绑定(bind)的处理程序打包在一个元组中,就像在 Boost.Asio 示例中的 connection::async_read() 中所做的那样。

关于c++ - 为什么 boost::asio::async_write 导致崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18537788/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com