boost socket示例卡在while循环中

时间:2018-02-02 05:02:16

标签: boost boost-asio

我正在尝试学习提升asio socket。在boost网页中有一个有趣的例子,它设置了一个监视超时的截止时间,并将async io改为同步时尚。但当我删除截止时间计时器时,程序卡在write_line中的while循环中,我不明白为什么可以设置连接但是套接字写入被卡住了。似乎写作从未完成,处理程序从未调用过,因此“ec”从未改变过。先感谢您!!

#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();”在构造函数中,输出为:

connect start
connect handler
system:0
connect done
write start
write handler 
system:0
write done

当行“check_deadline();”在构造函数中注释掉,输出是:

connect start
connect handler
system:0
connect done
write start

永远地卡在那里。

1 个答案:

答案 0 :(得分:0)

该特定示例的重点是阻止操作超时。这就是他们使用函数的async_ *风格的原因。

如果您不需要 ,请不要使用async_ *风格:

#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行,则过于简单。

不是通过使样品重新复杂化来“修复”样品,而是非常简单:

#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";
    }
}