0

我已经在这方面工作了很长时间,但没有成功。

想象一下,您的主要功能是这样的:

bool running = true;
int i = 0;
//waitHandler();
while(running)
    i++;

现在我想添加并调用一个计时器,它将运行设置为假,当它到期时。

void waitHandler(){ 

    boost::asio::io_service timerService;

    //create and bind the timer
    boost::asio::deadline_timer timer(timerService,
    boost::posix_time::milliseconds(2000));
    timer.wait();

    running = true;
    cout<<"WaitHandler triggered"<<endl;
}

当然这不起作用(当你取消注释上面的评论时),因为计时器会阻塞主线程。如果我想在不阻塞主要功能的情况下拥有此功能,该怎么办。

编辑:

//transfer some error message
void set_result(boost::system::error_code* a, boost::system::error_code b,deadline_timer &timer)
  {
     a->assign(b.value(),b.category());
  } 


 template<class SOCKET>
 void read_with_timeout(SOCKET & sock, unsigned int delay,
     const asio::mutable_buffers_1& buffers)
  {       
      //create error messages
      boost::system::error_code timer_result; 
      boost::system::error_code read_result; 

      //initialize timer
      deadline_timer timer(sock.get_io_service());        
      timer.expires_from_now(boost::posix_time::milliseconds(delay));
      timer.async_wait(boost::bind(set_result, &timer_result, _1,boost::ref(timer)));       

      //initialize receive mechanism
      sock.async_receive(buffers, boost::bind(set_result, &read_result, _1,boost::ref(timer)));    
      sock.get_io_service().reset();

      //should run for one handler
      while (sock.get_io_service().run_one())    
      {      
          if (read_result.value()==0){ //zero stands for, that the message was received properly.            
              timer.cancel();
              //cout<<"Message received: => Timer cancelled => RETURN!"<<endl;
              return;
          }

          if(timer.expires_from_now().total_milliseconds() <=0){                
              sock.cancel();                
              //cout<<"Timeout => Socket cancelled => RETURN!"<<endl;         
              return;
          }
      }   
 } 

如前所述,这几乎显示了预期的行为,但有一些问题:

  1. 为什么即使使用run_one,计时器的处理程序和接收的处理程序都可以被触发
  2. 当接收到 0 个字节时,为什么接收也会触发。对我来说,这听起来像是没有收到任何东西,并且该功能应该等待?
  3. 这是正确的方法吗?正如我所说的,我想接收或超时。(像ping)

实际上,当它们出现在 Wireshark 中时,它们的接收顺序是错误的——我猜它与 Wireshark 有关async_receive,它并没有真正等待传入的消息,而只是在函数调用之前获取缓冲区中的内容。

该怎么办?

4

4 回答 4

4

你让这比它需要的复杂得多。这个网站上有很多关于超时的问题, Boost.Asio 网站上有一个很好的例子。async_tcp_client 示例中的注释有一个很好的 ASCII 图表来解释这个场景

// This class manages socket timeouts by applying the concept of a deadline.
// Some asynchronous operations are given deadlines by which they must complete.
// Deadlines are enforced by an "actor" that persists for the lifetime of the
// client object:
//
//  +----------------+
//  |                |
//  | check_deadline |<---+
//  |                |    |
//  +----------------+    | async_wait()
//              |         |
//              +---------+
//
// If the deadline actor determines that the deadline has expired, the socket
// is closed and any outstanding operations are consequently cancelled.
//
// Connection establishment involves trying each endpoint in turn until a
// connection is successful, or the available endpoints are exhausted. If the
// deadline actor closes the socket, the connect actor is woken up and moves to
// the next endpoint.
//
//  +---------------+
//  |               |
//  | start_connect |<---+
//  |               |    |
//  +---------------+    |
//           |           |
//  async_-  |    +----------------+
// connect() |    |                |
//           +--->| handle_connect |
//                |                |
//                +----------------+
//                          :
// Once a connection is     :
// made, the connect        :
// actor forks in two -     :
//                          :
// an actor for reading     :       and an actor for
// inbound messages:        :       sending heartbeats:
//                          :
//  +------------+          :          +-------------+
//  |            |<- - - - -+- - - - ->|             |
//  | start_read |                     | start_write |<---+
//  |            |<---+                |             |    |
//  +------------+    |                +-------------+    | async_wait()
//          |         |                        |          |
//  async_- |    +-------------+       async_- |    +--------------+
//   read_- |    |             |       write() |    |              |
//  until() +--->| handle_read |               +--->| handle_write |
//               |             |                    |              |
//               +-------------+                    +--------------+
//
// The input actor reads messages from the socket, where messages are delimited
// by the newline character. The deadline for a complete message is 30 seconds.
//
// The heartbeat actor sends a heartbeat (a message that consists of a single
// newline character) every 10 seconds. In this example, no deadline is applied
// message sending.
//

您应该努力在您的应用程序中实现类似的设计。无需read_with_timeout()像您在问题中发布的那样编写函数来笨拙。使用async_read(),async_write()async_wait()足以为您提供所需的功能。

我认为您的部分困惑源于线程。不用多想,先了解基本概念。您将需要使用单个线程(调用的线程main())和单个线程io_service来启动。之后,您可以探索更高级的概念。如果您尝试将此代码集成到更大的应用程序中,那将是一个完全不同的问题。

学习前摄器设计模式也可能对您有所帮助。

于 2012-10-08T19:12:36.930 回答
1

您可以io_service::run在单独的线程中执行(并以某种方式同步对 的访问running)或在io_service循环中手动泵送while循环,使用run_one()/ poll()/poll_one() - 任何适合您的情况。

于 2012-10-04T14:18:56.130 回答
0

我找到了某种解决方案。我可以接受,即使有些事情我不明白。

//transfer some error message
void set_result(boost::system::error_code* a, boost::system::error_code b,deadline_timer &timer)
  {
     a->assign(b.value(),b.category());
  } 


 template<class SOCKET>
 void read_with_timeout(SOCKET & sock, unsigned int delay,
     const asio::mutable_buffers_1& buffers)
  {       
      //create error messages
      boost::system::error_code timer_result; 
      boost::system::error_code read_result; 

      //initialize timer
      deadline_timer timer(sock.get_io_service());        
      timer.expires_from_now(boost::posix_time::milliseconds(delay));
      timer.async_wait(boost::bind(set_result, &timer_result, _1,boost::ref(timer)));       

      //initialize receive mechanism
      sock.async_receive(buffers, boost::bind(set_result, &read_result, _1,boost::ref(timer)));    
      sock.get_io_service().reset();

      //should run for one handler
      while (sock.get_io_service().run_one())    
      {      
          if (read_result.value()==0){ //zero stands for, that the message was received properly.            
              timer.cancel();
              //cout<<"Message received: => Timer cancelled => RETURN!"<<endl;
              return;
          }

          if(timer.expires_from_now().total_milliseconds() <=0){                
              sock.cancel();                
              //cout<<"Timeout => Socket cancelled => RETURN!"<<endl;         
              return;
          }
      }   
 } 

这实际上适用于我的情况,取自 该线程引用的http://lists.boost.org/Archives/boost/2007/04/120339.php :如何在 boost asio 中设置阻塞套接字的超时?

我刚刚将其调整为 Boost 1.51。

有些事情对我来说仍然是模糊的,例如

  • io_service.run_one 实际上仍然会触发更多的事件处理程序,即使它应该只触发一个。
  • 还有一些来自计时器的事件我完全不感兴趣。我只想赶上超时而不是其他东西。(我不知道为什么还有其他东西)

无论如何,到目前为止我的问题已经解决了。

于 2012-10-05T15:54:23.983 回答
-1

您必须在其自己的线程上生成计时器,然后确保保护正在运行的变量免受并发访问。

于 2012-10-04T12:33:08.857 回答