私はBoost.Asioを広範囲に使用しましたが、私が理解していない単体テストの問題に遭遇しました。私はコンパイルBoost.Asioはわかりにくい例をブロックしました
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <boost/asio.hpp>
#define BOOST_TEST_MODULE My_Module
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/test/auto_unit_test.hpp>
using namespace std::string_literals;
using namespace std::chrono_literals;
namespace BA = boost::asio;
namespace BAI = BA::ip;
BOOST_AUTO_TEST_CASE(test)
{
std::mutex m;
std::condition_variable cv;
BA::io_service servicer;
auto io_work = std::make_unique<BA::io_service::work>(servicer);
auto thread = std::thread{[&]() {
servicer.run();
}};
auto received_response = false;
auto server_buf = std::array<std::uint8_t, 4096>{};
auto server_sock = BAI::tcp::socket{servicer};
auto acceptor = BAI::tcp::acceptor{servicer,
BAI::tcp::endpoint{BAI::tcp::v4(), 20123}};
acceptor.async_accept(server_sock, [&](auto&& ec) {
if (ec) {
BOOST_TEST_MESSAGE(ec.message());
}
BOOST_REQUIRE(!ec);
BOOST_TEST_MESSAGE("Accepted connection from " << server_sock.remote_endpoint() <<
", reading...");
BA::async_read(server_sock,
BA::buffer(server_buf),
[&](auto&& ec, auto&& bytes_read){
std::unique_lock<decltype(m)> ul(m);
received_response = true;
if (ec) {
BOOST_TEST_MESSAGE(ec.message());
}
BOOST_REQUIRE(!ec);
const auto str = std::string{server_buf.begin(),
server_buf.begin() + bytes_read};
BOOST_TEST_MESSAGE("Read: " << str);
ul.unlock();
cv.notify_one();
});
});
const auto send_str = "hello"s;
auto client_sock = BAI::tcp::socket{servicer, BAI::tcp::v4()};
client_sock.async_connect(BAI::tcp::endpoint{BAI::tcp::v4(), 20123},
[&](auto&& ec) {
if (ec) {
BOOST_TEST_MESSAGE(ec.message());
}
BOOST_REQUIRE(!ec);
BOOST_TEST_MESSAGE("Connected...");
BA::async_write(client_sock,
BA::buffer(send_str),
[&](auto&& ec, auto&& bytes_written) {
if (ec) {
BOOST_TEST_MESSAGE(ec.message());
}
BOOST_REQUIRE(!ec);
BOOST_TEST_MESSAGE("Written " << bytes_written << " bytes");
});
});
std::unique_lock<decltype(m)> ul(m);
cv.wait_for(ul, 2s, [&](){ return received_response; });
BOOST_CHECK(received_response);
io_work.reset();
servicer.stop();
if (thread.joinable()) {
thread.join();
}
}
:
g++ -std=c++17 source.cc -l boost_unit_test_framework -pthread -l boost_system -ggdb
出力は次のようになります。
Accepted connection from 127.0.0.1:51688, reading...
Connected...
Written 5 bytes
をし、それがタイムアウト私がダウンして非常に不自然な例に問題を低減しました。
デバッガを実行すると、async_read
ハンドラが呼び出されないことが示されます。何も実行されていないフェーズで実行を一時停止すると、メインスレッドがcondition_variable
(cv
)で待機し、io_service
スレッドがepoll_wait
に待機していることが示されます。
私はデッドロックしているようですが、どのように見えません。
最初の推測:クライアントがシャットダウンを発行していないため、送信されたデータ(4096)(send_string.size())を読み込もうとしているため、読み込みが完了していません。 –
@RichardHodgesしかし、私は応答が必要な場合、シャットダウンを発行すると、接続を受け取る前に接続が切断されますか?私は、送信者のバッファがOSのMTUの下にあるため、受信したパケットの後にサーバーソケットが読み取りハンドラを起動するため、私はあまりにも多くのことを想定していますか? – cmannett85
@RichardHodges書き込みハンドラの一番下に 'client_sock.shutdown(..)'を追加しようとしましたが、読み込みハンドラで 'End of stream'エラーが発生したばかりです。読取りバッファを5バイトに設定するとシステムが動作するようになりました。原則として間違いありませんが、あらかじめ送信サイズを知ることはできません。 – cmannett85