boost:: asio, ошибка асинхронного чтения
-
10-07-2019 - |
Вопрос
По какой-то причине это приводит к нарушению доступа, однако, не имея какой-либо подробной документации / справки по этому вопросу, я не уверен, где я делаю это неправильно.Исходя из того, что я видел на сайте boost, это должно быть правильно, и выводите содержимое каждого вызова asio::write от клиента в новую строку.Клиент, кажется, работает нормально.Хотя в этот момент сервер выходит из строя, но он еще ничего не отправил.
Нарушение доступа происходит в файле basic_stream_socket.hpp в строке 275.Причина, по-видимому, в том, что объект (boost:: asio:: stream_socket_service) не инициализирован (значение этого указателя равно 0xfeeefeee), однако я не понимаю, почему это не так.
Выходные данные программ:
Запуск сервера
Сервер::startAccept()
Сервер::handleAccept()
Соединение принято
Подключение::startRead()
Сервер::startAccept()
Подключение::handleRead()
ОШИБКА ЧТЕНИЯ:Операция ввода-вывода была прервана либо из-за завершения потока, либо из-за запроса приложения
Подключение::startRead()
Код
#include "precompiled.h"
#include "db.h"
class Connection
: public boost::enable_shared_from_this<Connection>
{
public:
typedef boost::shared_ptr<Connection> Pointer;
static Pointer create(boost::asio::io_service& ioService)
{
return Pointer(new Connection(ioService));
}
ip::tcp::socket& getSocket()
{
return socket;
}
void startRead()
{
std::cout << "Connection::startRead()" << std::endl;
socket.async_read_some(boost::asio::buffer(readBuffer),
boost::bind(&Connection::handleRead,this,_1,_2));
}
private:
Connection(asio::io_service& ioService)
: socket(ioService)
{
}
void handleWrite(const boost::system::error_code&,size_t)
{
}
void handleRead(const boost::system::error_code&error,size_t len)
{
std::cout << "Connection::handleRead()" << std::endl;
if(error)
{
std::cout << "READ ERROR: ";
std::cout << boost::system::system_error(error).what();
std::cout << std::endl;
}
else
{
std::cout << "read: ";
std::cout.write(readBuffer.data(),len);
std::cout << std::endl;
}
startRead();
}
boost::array<char, 256> readBuffer;
ip::tcp::socket socket;
};
class Server
{
public:
Server(asio::io_service& ioService)
:acceptor(ioService, ip::tcp::endpoint(ip::tcp::v4(), getPort()))
{
startAccept();
}
private:
void startAccept()
{
std::cout << "RServer::startAccept()" << std::endl;
Connection::Pointer newConn =
Connection::create(acceptor.io_service());
acceptor.async_accept(newConn->getSocket(),
boost::bind(&Server::handleAccept, this, newConn,
asio::placeholders::error));
}
void handleAccept(Connection::Pointer newConn,
const boost::system::error_code& error)
{
std::cout << "Server::handleAccept()" << std::endl;
if(error)
{
std::cout << "CONNECTION ERROR: ";
std::cout << boost::system::system_error(error).what();
std::cout << std::endl;
}
else
{
std::cout << "Connection accepted" << std::endl;
startAccept();
newConn->startRead();
}
}
ip::tcp::acceptor acceptor;
};
int main()
{
std::cout << "Start server" << std::endl;
asio::io_service ioService;
RemoteAdminServer server(ioService);
boost::system::error_code error;
ioService.run(error);
}
Решение
Вам следует изменить этот фрагмент кода:
void startRead()
{
std::cout << "Connection::startRead()" << std::endl;
socket.async_read_some(boost::asio::buffer(readBuffer),
boost::bind(&Connection::handleRead,this,_1,_2));
}
Для:
void startRead()
{
std::cout << "Connection::startRead()" << std::endl;
socket.async_read_some(boost::asio::buffer(readBuffer),
boost::bind(&Connection::handleRead,this->shared_from_this(),_1,_2));
}
Обратите внимание, что я прошел мимо общий указатель Для bind
.Это сохранит ваш Connection
экземпляр работает до тех пор, пока не будет вызван обработчик.В противном случае счетчик использования будет равен нулю в Server::startAccept
и объект будет удален.Затем, когда вызывается обработчик, память становится недействительной, и вы испытываете страшное "неопределенное поведение".
Другие советы
Я думаю, что ваш прогон существует, потому что у вас нет работы в рабочей очереди.
Вы должны запретить выходу из программы и уничтожению объекта службы.
Либо попробуйте это