C++/Asio:使用 async_write 发送数据时崩溃
C++/Asio : crash when sending data using async_write
我正在使用 Asio 来处理我的网络 class。
苦恼了好久,一直想不通原因。
一、代码:
// .h
#pragma once
#include <asio.hpp>
class Connection : public std::enable_shared_from_this<Connection>
{
public:
static std::shared_ptr<Connection> create(asio::io_context& IoContext);
asio::ip::tcp::socket& getSocket();
void start();
private:
Connection(asio::io_context& IoContext);
void startReading();
void sendPacket(std::string Packet);
void handle_read(const asio::error_code& error, size_t bytes);
void handle_write(const asio::error_code& error, size_t bytes);
void disconnect();
asio::ip::tcp::socket socket;
char packet[4096];
bool started;
};
class Network
{
public:
Network(asio::io_context& IoContext, unsigned short Port);
void startServer();
private:
void startAccept();
void handle_accept(std::shared_ptr<Connection> connection, const asio::error_code& error);
asio::io_context& ioContext;
asio::ip::tcp::acceptor acceptor;
bool started;
std::vector<std::shared_ptr<Connection>> connections;
};
// .cpp
Connection::Connection(asio::io_context& IoContext)
: socket(IoContext)
, started(false)
, packet("")
{
}
std::shared_ptr<Connection> Connection::create(asio::io_context& IoContext)
{
return std::shared_ptr<Connection>(new Connection(IoContext));
}
asio::ip::tcp::socket& Connection::getSocket()
{
return socket;
}
void Connection::start()
{
std::cout << "Connection::start();" << std::endl;
if (!started)
{
startReading();
started = true;
}
}
void Connection::sendPacket(std::string Packet)
{
socket.async_send(asio::buffer(Packet), [this](const asio::error_code& error, size_t bytes)
{ handle_write(error, bytes); });
}
void Connection::startReading()
{
socket.async_receive(asio::buffer(packet), [this](const asio::error_code& error, size_t bytes)
{ handle_read(error, bytes); });
}
void Connection::handle_write(const asio::error_code& error, size_t bytes)
{
std::cout << "WRITE : " << error.message() << " size : " << bytes << std::endl;
}
void Connection::handle_read(const asio::error_code& error, size_t bytes)
{
if (error)
{
std::cout << "error:" << error.message();
disconnect();
}
else
{
if (bytes > 0)
{
packet[bytes] = 0;
std::string response = ...;
sendPacket(response);
}
}
}
Network::Network(asio::io_context& IoContext, unsigned short Port)
: ioContext(IoContext)
, acceptor(ioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), Port))
, started(false)
{
std::cout << "Server::Server();" << std::endl;
}
void Network::startServer()
{
std::cout << "Server::startServer();" << std::endl;
if (!started)
{
startAccept();
started = true;
}
}
void Network::startAccept()
{
std::cout << "Server::startAccept();" << std::endl;
std::shared_ptr<Connection> connection = Connection::create(ioContext);
connections.push_back(connection);
asio::error_code er;
acceptor.async_accept(connection->getSocket(), std::bind(&Network::handle_accept, this, connection, er));
}
void Network::handle_accept(std::shared_ptr<Connection> connection, const asio::error_code& error)
{
std::cout << "Server::handle_accept();" << std::endl;
if (!error)
{
std::cout << "Ok" << std::endl;
connection->start();
}
startAccept();
}
(我从cpp中删除了不必要的功能以使其更简洁,如果缺少某些功能请不要感到惊讶)
基本上,当我从 handle_read 函数中 sendPacket(something)
时它会崩溃。
我找到了两个修复程序:
- 创建并使用成员
std::string
,则handle_read(...)
中的代码变为
if (bytes > 0)
{
packet[bytes] = 0;
std::string response = ...;
sendPacket(my_member_string);
}
- 或 我在
sendPacket(...)
中创建了一个 std::string*
:
void Connection::sendPacket(std::string Packet)
{
std::string *copy;
socket.async_send(asio::buffer(copy), [this](const asio::error_code& error, size_t bytes)
{ handle_write(error, bytes); });
}
不删除它(如果我这样做,它会以同样的方式崩溃)。
那么,我的问题是:为什么 response
会导致崩溃?我读了很多关于“一生”的同一期,你能告诉我更多吗? response
的这段代码到底发生了什么?
另外,如果不是上述错误,修复此错误的干净方法是什么?
顺便说一句,我没有使用Boost。
提前致谢
您不应该 在 ..._async 函数中的 lambda 中捕获 [this]
指针。因为 lambda 将超过 this 指针并且 this 将指向 lambda 调用中的无效地址。
在 lambda 中使用 [self=shared_from_this()]
并使用 self,因此该对象将通过异步调用使用共享指针。
我正在使用 Asio 来处理我的网络 class。 苦恼了好久,一直想不通原因。
一、代码:
// .h
#pragma once
#include <asio.hpp>
class Connection : public std::enable_shared_from_this<Connection>
{
public:
static std::shared_ptr<Connection> create(asio::io_context& IoContext);
asio::ip::tcp::socket& getSocket();
void start();
private:
Connection(asio::io_context& IoContext);
void startReading();
void sendPacket(std::string Packet);
void handle_read(const asio::error_code& error, size_t bytes);
void handle_write(const asio::error_code& error, size_t bytes);
void disconnect();
asio::ip::tcp::socket socket;
char packet[4096];
bool started;
};
class Network
{
public:
Network(asio::io_context& IoContext, unsigned short Port);
void startServer();
private:
void startAccept();
void handle_accept(std::shared_ptr<Connection> connection, const asio::error_code& error);
asio::io_context& ioContext;
asio::ip::tcp::acceptor acceptor;
bool started;
std::vector<std::shared_ptr<Connection>> connections;
};
// .cpp
Connection::Connection(asio::io_context& IoContext)
: socket(IoContext)
, started(false)
, packet("")
{
}
std::shared_ptr<Connection> Connection::create(asio::io_context& IoContext)
{
return std::shared_ptr<Connection>(new Connection(IoContext));
}
asio::ip::tcp::socket& Connection::getSocket()
{
return socket;
}
void Connection::start()
{
std::cout << "Connection::start();" << std::endl;
if (!started)
{
startReading();
started = true;
}
}
void Connection::sendPacket(std::string Packet)
{
socket.async_send(asio::buffer(Packet), [this](const asio::error_code& error, size_t bytes)
{ handle_write(error, bytes); });
}
void Connection::startReading()
{
socket.async_receive(asio::buffer(packet), [this](const asio::error_code& error, size_t bytes)
{ handle_read(error, bytes); });
}
void Connection::handle_write(const asio::error_code& error, size_t bytes)
{
std::cout << "WRITE : " << error.message() << " size : " << bytes << std::endl;
}
void Connection::handle_read(const asio::error_code& error, size_t bytes)
{
if (error)
{
std::cout << "error:" << error.message();
disconnect();
}
else
{
if (bytes > 0)
{
packet[bytes] = 0;
std::string response = ...;
sendPacket(response);
}
}
}
Network::Network(asio::io_context& IoContext, unsigned short Port)
: ioContext(IoContext)
, acceptor(ioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), Port))
, started(false)
{
std::cout << "Server::Server();" << std::endl;
}
void Network::startServer()
{
std::cout << "Server::startServer();" << std::endl;
if (!started)
{
startAccept();
started = true;
}
}
void Network::startAccept()
{
std::cout << "Server::startAccept();" << std::endl;
std::shared_ptr<Connection> connection = Connection::create(ioContext);
connections.push_back(connection);
asio::error_code er;
acceptor.async_accept(connection->getSocket(), std::bind(&Network::handle_accept, this, connection, er));
}
void Network::handle_accept(std::shared_ptr<Connection> connection, const asio::error_code& error)
{
std::cout << "Server::handle_accept();" << std::endl;
if (!error)
{
std::cout << "Ok" << std::endl;
connection->start();
}
startAccept();
}
(我从cpp中删除了不必要的功能以使其更简洁,如果缺少某些功能请不要感到惊讶)
基本上,当我从 handle_read 函数中 sendPacket(something)
时它会崩溃。
我找到了两个修复程序:
- 创建并使用成员
std::string
,则handle_read(...)
中的代码变为
if (bytes > 0)
{
packet[bytes] = 0;
std::string response = ...;
sendPacket(my_member_string);
}
- 或 我在
sendPacket(...)
中创建了一个std::string*
:
void Connection::sendPacket(std::string Packet)
{
std::string *copy;
socket.async_send(asio::buffer(copy), [this](const asio::error_code& error, size_t bytes)
{ handle_write(error, bytes); });
}
不删除它(如果我这样做,它会以同样的方式崩溃)。
那么,我的问题是:为什么 response
会导致崩溃?我读了很多关于“一生”的同一期,你能告诉我更多吗? response
的这段代码到底发生了什么?
另外,如果不是上述错误,修复此错误的干净方法是什么?
顺便说一句,我没有使用Boost。
提前致谢
您不应该 在 ..._async 函数中的 lambda 中捕获 [this]
指针。因为 lambda 将超过 this 指针并且 this 将指向 lambda 调用中的无效地址。
在 lambda 中使用 [self=shared_from_this()]
并使用 self,因此该对象将通过异步调用使用共享指针。