[英]Boost.Asio contrived example inexplicably blocking
我已經廣泛使用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
。
我似乎陷入僵局,但看不到如何。
這是函數定義的工作方式,它確切地等待緩沖區具有空間的字節數( http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/reference/async_read /overload1.html )。
請嘗試以下一種方法: http : //www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/reference/async_read/overload2.html
您可以提供一個回調函數來決定讀取是否完成,並且可以包括在編寫者編寫其消息后(如果您確定了無死鎖的方式)等待並檢查另一個通道提供的長度(或者在正確的消息之前。
添加此完成條件使其起作用:
[&](auto&& ec, auto&& bytes_read){
return bytes_read < 5 ? 5 - bytes_read : 0;
},
@codeshot提供的答案是正確的,但這是幾種解決方案之一-最合適的解決方案完全取決於您在TCP連接上使用的協議。
例如,在傳統的鍵長-值樣式協議中,您將執行兩次讀取:
boost::asio::async_read
(或等效方法)讀入固定長度緩沖區以獲得固定長度報頭 聊天服務器示例代碼中有一個很好的示例。
如果您使用的是HTTP或RTSP(后者是我想做的),那么您就不知道會有多少數據輸入,您所關心的只是接收到一個數據包中的數據(我知道這過於簡單了)由於響應中包含Content-Length
標頭,分塊的傳輸編碼等,請耐心等待)。 為此,您需要async_read_some
(或等效方法),請參見HTTP服務器示例 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.