0

私はすでにこれに長い間取り組んでいますが、成功していません。

あなたの主な機能が次のようなものだと想像してみてください。

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

次に、タイマーを追加して呼び出します。タイマーは、有効期限が切れたときに実行をfalseに設定します。

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

もちろん、タイマーがメインスレッドをブロックするため、これは機能しません(uが上記のコメントのコメントを解除した場合)。main関数をブロックせずにこの機能を使用したい場合はどうすればよいですか。

編集:

//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のように)

async_receive実際、パケットはWiresharkに表示されたときに間違った順序で受信されます。これは、着信メッセージを実際に待機するのではなく、関数呼び出しの前にバッファにあるものを取得するだけであると関係があると思います。

何をすべきか?

4

4 に答える 4

4

あなたはこれを必要以上に複雑にしています。このサイトにはタイムアウトに関する質問が山ほどあり、Boost.AsioのWebサイトには素晴らしい例があります。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。その後、より高度な概念を探索できます。このコードをより大きなアプリケーションに統合しようとしている場合、それはまったく別の質問です。

Proactorのデザインパターンを研究することもあなたに役立つかもしれません。

于 2012-10-08T19:12:36.930 に答える
1

別のスレッドで実行するio_service::run(そして何らかの方法でへのアクセスを同期する)か、 //を使用してループ内でループを手動でrunningポンピングすることができます-あなたの場合に適切なものは何でも。io_servicewhilerun_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から取得されました: boostasioでソケットをブロックする際のタイムアウトを設定するにはどうすればよいですか?

Boost1.51に適合させました。

たとえば、いくつかのことがまだ私にはわかりません。

  • io_service.run_oneは、実際には1つだけを起動することになっていますが、実際にはさらに多くのイベントハンドラーを起動します。
  • また、私にはまったく興味のないタイマーからのイベントがあります。タイムアウトをキャッチしたいだけで、他のものはキャッチしたくない。(なぜ他のものがあるのか​​わかりません)

いずれにせよ、私の問題はこれまでに解決されました。

于 2012-10-05T15:54:23.983 に答える
-1

タイマーを独自のスレッドで生成してから、実行中の変数を同時アクセスから保護する必要があります。

于 2012-10-04T12:33:08.857 に答える