我已经广泛使用过Boost.Asio,但是我遇到了一个我不明白的单元测试问题。我把这个问题简化为一个非常人为的例子:
Arduino: 1.8.4 (Windows 8.1), Board: "Arduino Pro or Pro Mini, ATmega168 (3.3V, 8 MHz)"
Archiving built core (caching) in: C:\Users\pxb07\AppData\Local\Temp\arduino_cache_814882\core\core_arduino_avr_pro_cpu_8MHzatmega168_0c812875ac70eb4a9b385d8fb077f54c.a
Sketch uses 3284 bytes (22%) of program storage space. Maximum is 14336 bytes.
Global variables use 335 bytes (32%) of dynamic memory, leaving 689 bytes for local variables. Maximum is 1024 bytes.
C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude -CC:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf -v -patmega168 -carduino -PCOM8 -b19200 -D -Uflash:w:C:\Users\pxb07\AppData\Local\Temp\arduino_build_381498/SoftwareSerialExample.ino.hex:i
avrdude: Version 6.3, compiled on Jan 17 2017 at 12:00:53
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2014 Joerg Wunsch
System wide configuration file is "C:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf"
Using Port : COM8
Using Programmer : arduino
Overriding Baud Rate : 19200
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x28
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x28
avrdude done. Thank you.
Problem uploading to board. See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions.
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
我编译的:
#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
。
我似乎陷入僵局,但无法理解。
答案 0 :(得分:4)
这是函数定义的工作方式,它等待缓冲区为(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
你可以给出一个回调来决定读取是否完整,并且可以包括在编写器写入消息后等待并检查另一个通道提供的长度(如果你已经确定了无死锁的方式) )或恰好在信息正确之前。
添加此完成条件使其有效:
A.sort((a,b) => Math.abs(a) - Math.abs(b))
答案 1 :(得分:1)
@codeshot提供的答案是正确的,但它是几种解决方案中的一种 - 最合适的完全取决于您在TCP连接中使用的协议。
例如,在传统的Key-Length-Value样式协议中,您将执行两次读取:
boost::asio::async_read
(或等效内容)读入固定长度缓冲区以获取固定长度标题chat server example code中有一个很好的例子。
如果您使用的是HTTP或RTSP(后者就是我想要做的事情),那么您就不知道数据的来源有多少,您所关心的只是收到数据包的价值数据(我知道这是一个过于简单化的问题,因为响应中的Content-Length
标题,分块转移编码等等,但是请耐心等待。为此,您需要async_read_some
(或等效),请参阅HTTP server example。