boost :: asio, errore di lettura asincrono
-
10-07-2019 - |
Domanda
Per qualche motivo questo si traduce in una violazione di accesso, tuttavia non avendo alcuna documentazione / aiuto dettagliati su questo non sono sicuro di dove stia sbagliando. Da quando ho seguito ciò che ho visto sul sito boost, questo dovrebbe essere corretto e stampare il contenuto di ogni chiamata asio :: write dal client su una nuova linea. Il client sembra funzionare bene. Anche se al momento il server si arresta in modo anomalo, ma non ha ancora inviato nulla.
La violazione di accesso si verifica in basic_stream_socket.hpp alla riga 275. La causa sembra essere che l'oggetto (boost :: asio :: stream_socket_service) non sia inizializzato (il valore di questo puntatore è 0xfeeefeee), tuttavia non capisco perché non lo è.
L'output dei programmi:
Avvia il server
Server :: startAccept ()
Server :: handleAccept ()
Connessione accettata
Collegamento :: startRead ()
Server :: startAccept ()
Collegamento :: handleRead ()
READ ERROR: l'operazione di I / O è stata interrotta a causa della chiusura di un thread o di una richiesta dell'applicazione
Connection :: startRead ()
Il codice
#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);
}
Soluzione
Devi modificare questo frammento di codice:
void startRead()
{
std::cout << "Connection::startRead()" << std::endl;
socket.async_read_some(boost::asio::buffer(readBuffer),
boost::bind(&Connection::handleRead,this,_1,_2));
}
a:
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));
}
Nota che ho passato un puntatore condiviso a bind
. Ciò manterrà la tua istanza Connection
fino a quando non verrà invocato il gestore. Altrimenti, il conteggio degli usi va a zero in Server :: startAccept
e l'oggetto viene eliminato. Quindi, quando viene richiamato il gestore, la memoria non è valida e si verifica il temuto comportamento "indefinito". & Quot;
Altri suggerimenti
Penso che la tua corsa esista perché non hai più lavoro nella coda di lavoro.
Devi impedire che la corsa esca e distrugga il tuo oggetto di servizio.
Prova questo:
boost :: asio :: :: io_service lavoro
o semplicemente fai un
do { ioService.run( error ); } while( !error );