ゲームループと書いていますが、要はタイマーによる定期実行プログラムです。
io_service::run()の使いどころで嵌りました。
async系関数を次々記述していき、最後にio_service::run()を使用することで、非同期処理が終わるまで待機することになるので、ゲームループでフレームごとに通信を行う場合には、フレームの最初でio_service::reset()を呼んで非同期処理をリセットし、フレームの最後でio_service::run()を呼び、非同期処理が終わるまで待機することになります。
void update()
{
io_service.reset();
async_proc();
io_service.run();
}
以下、サンプルコード:
クライアントから"request\n"を送り、サーバーがそれを受け、"response\n"を返してクライアントがそれを受け取る、を繰り返すプログラムです。
クライアント:
#include <iostream> #include <string> #include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/bind.hpp> namespace asio = boost::asio; namespace ip = asio::ip; class Game { asio::io_service& io_service_; ip::tcp::socket socket_; asio::streambuf send_buffer_; asio::streambuf receive_buffer_; public: Game(asio::io_service& io_service) : io_service_(io_service), socket_(io_service) { socket_.connect(ip::tcp::endpoint(ip::address::from_string("127.0.0.1"), 31400)); } void update() { io_service_.reset(); async_send(); async_receive(); io_service_.run(); } private: void async_send() { const std::string request = "request\n"; std::ostream os(&send_buffer_); os << request; asio::async_write(socket_, send_buffer_.data(), boost::bind(&Game::send_end, this, _1)); } void send_end(const boost::system::error_code& error) { std::cout << "request : " << asio::buffer_cast<const char*>(send_buffer_.data()) << std::endl; send_buffer_.consume(send_buffer_.size()); } void async_receive() { asio::async_read_until(socket_, receive_buffer_, '\n', boost::bind(&Game::receive_end, this, _1)); } void receive_end(const boost::system::error_code& error) { std::cout << "response : " << asio::buffer_cast<const char*>(receive_buffer_.data()) << std::endl; receive_buffer_.consume(receive_buffer_.size()); } }; int main() { asio::io_service io_service; Game game(io_service); for (;;) { // てきとーなタイマー game.update(); boost::this_thread::sleep(boost::posix_time::seconds(1)); } }
サーバー:
#include <string> #include <boost/asio.hpp> #include <boost/bind.hpp> namespace asio = boost::asio; namespace ip = asio::ip; class server { asio::io_service& io_service_; ip::tcp::socket socket_; asio::streambuf request_buffer_; asio::streambuf response_buffer_; public: server(asio::io_service& io_service) : io_service_(io_service), socket_(io_service) {} ip::tcp::socket& get_socket() { return socket_; } void start() { receive_start(); } void receive_start() { asio::async_read_until(socket_, request_buffer_, '\n', boost::bind(&server::receive_end, this, _1)); } void receive_end(const boost::system::error_code& error) { if (error) { std::cout << "receive error : " << error.message() << std::endl; } else { std::cout << "request : " << asio::buffer_cast<const char*>(request_buffer_.data()) << std::endl; request_buffer_.consume(request_buffer_.size()); const std::string response = "response\n"; std::ostream os(&response_buffer_); os << response; asio::async_write(socket_, response_buffer_.data(), boost::bind(&server::send_end, this, _1)); } } void send_end(const boost::system::error_code& error) { if (error) { std::cout << "send error : " << error.message() << std::endl; } else { std::cout << "response : " << asio::buffer_cast<const char*>(response_buffer_.data()) << std::endl; } response_buffer_.consume(response_buffer_.size()); receive_start(); } }; int main() { asio::io_service io_service; server connection(io_service); ip::tcp::acceptor acc(io_service, ip::tcp::endpoint(ip::tcp::v4(), 31400)); acc.accept(connection.get_socket()); connection.start(); io_service.run(); for (;;) {} }