问题描述
我正在尝试学习boost asio套接字.在boost网页中有一个有趣的示例,该示例设置了截止时间来监视超时并更改async io以同步io方式.但是,当我删除最后期限计时器时,程序陷入了write_line的while循环中,我不明白为什么可以建立连接,但是套接字写却被阻塞了.看来编写从未完成,处理程序也从未调用过,因此"ec"从未改变.先感谢您!!
I am trying to learn boost asio socket. there is one interesting example in boost web page which set a deadline time to monitor the timeout and change async io to sync io fashion. but when I remove the deadline timer the program stuck in while loop in write_line, I don't understand why the connection can be setup but the socket write is stuck. it seems that the writing never finished ,the handler never called so the "ec" never changed. Thank you in advance!!
#include <boost/asio/connect.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
class client
{
public:
client()
: socket_(io_service_),
deadline_(io_service_)
{
deadline_.expires_from_now(boost::posix_time::seconds(10));
check_deadline(); // without this line which means without the this timer
//async_wait, the code stuck in write_line io_service_.run_one() loop .
}
void connect_handler(const boost::system::error_code& error,boost::system::error_code *er)
{
std::cerr<<"connect handler"<<std::endl;
*er = error;
std::cerr<<error<<std::endl;
}
void connect(const std::string& host, const std::string& service)
{
tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
std::cerr<<"connect start"<<std::endl;
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_connect(socket_, iter, bind(&client::connect_handler,this,_1,&ec));
do
{io_service_.run_one();
}while (ec == boost::asio::error::would_block);
std::cerr<<"connect done"<<std::endl; // always works fine!
if (ec || !socket_.is_open())
throw boost::system::system_error(
ec ? ec : boost::asio::error::operation_aborted);
}
void write_handler(const boost::system::error_code& error, std::size_t size,boost::system::error_code* er )
{
std::cerr<<"write handler "<<std::endl;
*er=error;
std::cerr<<error<<std::endl;
}
void write_line(const std::string& line)
{
std::cerr<<"write start"<<std::endl;
std::string data = line + "\n";
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_write(socket_, boost::asio::buffer(data), bind(&client::write_handler,this,_1,_2,&ec));
do
{
io_service_.run_one(); //stuck here without "check_deadline();" in constructor.
}while (ec == boost::asio::error::would_block);
std::cerr<<"write done";
if (ec)
throw boost::system::system_error(ec);
}
private:
void check_deadline()
{
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
{
boost::system::error_code ignored_ec;
socket_.close(ignored_ec);
deadline_.expires_at(boost::posix_time::pos_infin);
throw boost::system::system_error(ignored_ec);
}
deadline_.async_wait(std::bind(&client::check_deadline, this));
}
boost::asio::io_service io_service_;
tcp::socket socket_;
deadline_timer deadline_;
};
int main()
{
try
{
client c,d;
c.connect("216.58.194.164", "80");// google IP.
c.write_line("test");
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
在行"check_deadline();"中未添加注释在构造函数中,输出为:
Without comment out line "check_deadline();" in constructor the output is :
connect start
connect handler
system:0
connect done
write start
write handler
system:0
write done
当行"check_deadline();"时在构造函数中注释掉,输出为:
when the line "check_deadline();" comment out in constructor, the output is :
connect start
connect handler
system:0
connect done
write start
并永远停留在那里.
推荐答案
该特定示例的全部要点是阻止操作超时.这就是为什么他们使用函数async_ *的原因.
The whole point of that particular example is to have timeouts on blocking operations. This is why they use the async_* flavour of functions.
如果您不需要那个,则完全不要使用async_ *风味:
If you don't need that, don't use the async_* flavour at all:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
class client {
public:
client() : socket_(io_service_) { }
void connect(const std::string &host, const std::string &service) {
tcp::resolver::query query(host, service);
socket_.close();
boost::asio::connect(socket_, tcp::resolver(io_service_).resolve(query));
}
std::string read_line() {
boost::system::error_code ec;
boost::asio::read_until(socket_, input_buffer_, '\n', ec);
if (ec == boost::asio::error::eof)
socket_.close();
else if (ec)
throw boost::system::system_error(ec);
std::string line;
std::getline(std::istream(&input_buffer_), line);
return line;
}
void write_line(const std::string &line) {
std::string data = line + "\n";
boost::asio::write(socket_, boost::asio::buffer(data));
}
private:
boost::asio::io_service io_service_;
tcp::socket socket_;
boost::asio::streambuf input_buffer_;
};
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp <host> <port> <message>\n";
return 1;
}
client c;
c.connect(argv[1], argv[2]);
boost::posix_time::ptime time_sent = boost::posix_time::microsec_clock::universal_time();
c.write_line(argv[3]);
for (;;) {
std::string line = c.read_line();
std::cout << "Received '" << line << "'\n";
if (line == argv[3])
break;
}
boost::posix_time::ptime time_received = boost::posix_time::microsec_clock::universal_time();
std::cout << "Round trip time: ";
std::cout << (time_received - time_sent).total_microseconds();
std::cout << " microseconds\n";
} catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
这要简单得多.实际上,如果到达的数据包一次包含多于1行,这太简单了.
That's a lot simpler. In fact, it's too simple in case the packets arriving contain more than 1 line at a time.
与其通过重新复杂化来固定"样本,还可以更加简单:
Instead of "fixing" the sample by re-complicating it, it can be ENORMOUSLY simpler:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp <host> <port> <message>\n";
return 1;
}
tcp::iostream c(argv[1], argv[2]);
boost::posix_time::ptime time_sent = boost::posix_time::microsec_clock::universal_time();
c << argv[3] << "\n";
std::string line;
while (getline(c, line)) {
std::cout << "Received '" << line << "'\n";
if (line == argv[3])
break;
}
boost::posix_time::ptime time_received = boost::posix_time::microsec_clock::universal_time();
std::cout << "Round trip time: ";
std::cout << (time_received - time_sent).total_microseconds();
std::cout << " microseconds\n";
} catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
这篇关于boost套接字示例卡在while循环中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!