つまり、次の 2 つのオプションがあります。
- コードを非同期 (
acceptor::async_accept()
and async_read
) に変更し、 を介してイベント ループ内で実行し、 を介しio_service::run()
てキャンセルしio_service::stop()
ます。
- シグナルなどの低レベルの仕組みでブロック呼び出しを強制的に中断させます。
最初のオプションをお勧めします。これは、移植性が高く、保守が容易である可能性が高いためです。理解しておくべき重要な概念は、io_service::run()
保留中の作業がある限りブロックするということです。がio_service::stop()
呼び出されると、ブロックされているすべてのスレッドio_service::run()
をできるだけ早く返そうとします。同期操作がイベント ループ内で呼び出された場合でも、acceptor::accept()
やなどの同期操作は中断されません。はノンブロッキング コールであるため、ブロックされたスレッドと同期するには、 などの別のメカニズムを使用する必要があるsocket::receive()
ことに注意してください。io_service::stop()
io_service::run()
thread::join()
以下は、10 秒間実行され、ポート 8080 をリッスンする例です。
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <iostream>
void StartAccept( boost::asio::ip::tcp::acceptor& );
void ServerThreadFunc( boost::asio::io_service& io_service )
{
using boost::asio::ip::tcp;
tcp::acceptor acceptor( io_service, tcp::endpoint( tcp::v4(), 8080 ) );
// Add a job to start accepting connections.
StartAccept( acceptor );
// Process event loop.
io_service.run();
std::cout << "Server thread exiting." << std::endl;
}
void HandleAccept( const boost::system::error_code& error,
boost::shared_ptr< boost::asio::ip::tcp::socket > socket,
boost::asio::ip::tcp::acceptor& acceptor )
{
// If there was an error, then do not add any more jobs to the service.
if ( error )
{
std::cout << "Error accepting connection: " << error.message()
<< std::endl;
return;
}
// Otherwise, the socket is good to use.
std::cout << "Doing things with socket..." << std::endl;
// Perform async operations on the socket.
// Done using the socket, so start accepting another connection. This
// will add a job to the service, preventing io_service::run() from
// returning.
std::cout << "Done using socket, ready for another connection."
<< std::endl;
StartAccept( acceptor );
};
void StartAccept( boost::asio::ip::tcp::acceptor& acceptor )
{
using boost::asio::ip::tcp;
boost::shared_ptr< tcp::socket > socket(
new tcp::socket( acceptor.get_io_service() ) );
// Add an accept call to the service. This will prevent io_service::run()
// from returning.
std::cout << "Waiting on connection" << std::endl;
acceptor.async_accept( *socket,
boost::bind( HandleAccept,
boost::asio::placeholders::error,
socket,
boost::ref( acceptor ) ) );
}
int main()
{
using boost::asio::ip::tcp;
// Create io service.
boost::asio::io_service io_service;
// Create server thread that will start accepting connections.
boost::thread server_thread( ServerThreadFunc, boost::ref( io_service ) );
// Sleep for 10 seconds, then shutdown the server.
std::cout << "Stopping service in 10 seconds..." << std::endl;
boost::this_thread::sleep( boost::posix_time::seconds( 10 ) );
std::cout << "Stopping service now!" << std::endl;
// Stopping the io_service is a non-blocking call. The threads that are
// blocked on io_service::run() will try to return as soon as possible, but
// they may still be in the middle of a handler. Thus, perform a join on
// the server thread to guarantee a block occurs.
io_service.stop();
std::cout << "Waiting on server thread..." << std::endl;
server_thread.join();
std::cout << "Done waiting on server thread." << std::endl;
return 0;
}
実行中に、2 つの接続を開きました。出力は次のとおりです。
10 秒後にサービスを停止します...
接続待ち
ソケットで物事を行う...
ソケットの使用が完了し、別の接続の準備が整いました。
接続待ち
ソケットで物事を行う...
ソケットの使用が完了し、別の接続の準備が整いました。
接続待ち
ただいまサービス停止中!
サーバースレッドで待機中...
サーバー スレッドが終了しています。
サーバー スレッドでの待機が完了しました。