我已經廣泛使用了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,但是如果我需要響應,那麼確實發出關閉會導致連接在我收到之前關閉?我想我是因爲發送緩衝區在操作系統的MTU之下,服務器套接字會在接收到數據包後觸發讀處理程序 - 我是否假設太多了? – cmannett85
@RichardHodges我應該補充一點,我嘗試在寫入處理程序的底部添加一個'client_sock.shutdown(..)',但它只是在讀取處理程序中觸發了'結束流'錯誤。將讀緩衝區設置爲5字節使得系統正常工作,所以你原則上是絕對正確的,但顯然我無法預先知道發送大小。 – cmannett85