boost :: asio、非同期読み取りエラー
-
10-07-2019 - |
質問
何らかの理由でこれによりアクセス違反が発生しますが、詳細なドキュメント/ヘルプがないため、どこで間違っているのかわかりません。私がブーストサイトで見たものを通り過ぎてから、これは正しいはずであり、クライアントからの各asio :: write呼び出しの内容を新しい行に出力します。クライアントは正常に動作しているようです。その時点でサーバーはクラッシュしますが、まだ何も送信していません。
アクセス違反は、275行目のbasic_stream_socket.hppで発生します。原因は、オブジェクト(boost :: asio :: stream_socket_service)が初期化されていないため(このポインターの値は0xfeeefeeeです)、なぜそうなっていないのかはわかりません。
プログラムの出力:
サーバーの起動
Server :: startAccept()
Server :: handleAccept()
接続が受け入れられました
Connection :: startRead()
Server :: startAccept()
Connection :: handleRead()
読み取りエラー:スレッドが終了したか、アプリケーション要求があるため、I / O操作が中止されました
Connection :: 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));
}
to:
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
で使用カウントがゼロになり、オブジェクトが削除されます。次に、ハンドラーが呼び出されると、メモリが無効になり、恐ろしい「未定義の動作」が発生します。
他のヒント
作業キューに作業が残っていないため、実行が存在すると思います。
実行が終了してサービスオブジェクトが破壊されるのを防ぐ必要があります。
これを試してください:
boost :: asio :: io_service :: work
または単に
do { ioService.run( error ); } while( !error );