1. boost::asio::streambuf と組み合わせる場合
うっかり,
boost::asio::async_read(socket, streambuf, handler);
見たいに書くと, 永遠に handler
が起動されない可能性があるので注意しましょう.
これは, async_read
は指定されたサイズ分読みを行い, デフォルトでは 65535 になっているからです.
少量のデータを送受信する場合は, boost::asio::transfer_at_least
等と一緒に使用しましょう.
// 少なくとも 4 byte 読むが, 一度の read でそれ以上読めたら handler が起動される boost::asio::async_read(socket, streambuf, boost::asio::transfer_at_least(4), handler);
2. coroutine を使用かつ socket が close された場合
ドキュメンにも記載されていますが, read()
/ async_read()
は, 期待したサイズ分を読む前に socket の終端 (EOF) を読むと, boost::asio::error::eof
をエラーコードに指定して終了してしまいます.
そのため, 以下のコードのように try-catch でエラーハンドリングすると, 何バイト読んだのかが分からず, 読み込んだデータを処理できない場合があります.
最悪, 読み込んだデータが捨てられてしまいます.
try { auto const size = boost::asio::async_read(socket, boost::asio::buffer(buf), yield); } catch (boost::system::system_error& e) { if (e.code() == boost::asio::error::eof) { // 何バイト読めたのか分からない } }
以上を考慮すると, error_code
を指定してあげるのが良いと思われます.
auto ec = boost::system::error_code{}; auto const size = boost::asio::async_read(socket, boost::asio::buffer(buf), yield[ec]); if (ec && ec != boost::asio::error::eof) { throw boost::system::system_error{ec}; } // 何か有益な処理 // ... if (ec && ec == boost::asio::error::eof) { socket.close(); return; }