0
  • プラットフォーム: Windows 7 プロフェッショナル 64 ビット
  • コンパイラ: VS2010 Express
  • ブースト: バージョン 1.49
  • Plugin System : OBSE 20 (Bethesda の Oblivion ゲーム用)

async udp の例に基づいたクラスがあります。io サービス自体をスレッドとして実行します。クラスのコードは次のとおりです。

    // udp buffer queues
    extern concurrent_queue<udp_packet> udp_input_queue; // input from external processes
    extern concurrent_queue<udp_packet> udp_output_queue; // output to external processes

    using boost::asio::ip::udp;
    class udp_server
    {
    public:
        udp_server(boost::asio::io_service& io_service, short port)
            : io_service_(io_service),
              socket_(io_service_, udp::endpoint(boost::asio::ip::address_v4::from_string(current_address), port))//, // udp::v4()  
        {
            // start udp receive
            socket_.async_receive_from(
                boost::asio::buffer(recv_buf), sender_endpoint_,
                boost::bind(&udp_server::handle_receive_from, this,
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred));  

            send_timer_ = NULL;            
        }

        ~udp_server(){
            io_service_.stop();
            if(send_timer_){
                send_timer_->cancel();
                delete send_timer_;
            }
        }

        void start(){
            // start send timer                
            send_timer_ = new boost::asio::deadline_timer(io_service_, boost::posix_time::milliseconds(500));
            send_timer_restart();
        }

        void handle_send_to(const boost::system::error_code& error, size_t bytes_recvd);
        void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd);

        //void handle_send_timer(const boost::system::error_code& error);
        void handle_send_timer();
        void send_timer_restart();

        void stop()
        {
            io_service_.stop();
        }

        private:
            boost::asio::io_service& io_service_;
            udp::socket socket_;
            udp::endpoint sender_endpoint_; 
            std::vector<udp::endpoint> clientList;
            //std::auto_ptr<boost::asio::io_service::work> busy_work;
            udp_buffer recv_buf;
            boost::asio::deadline_timer* send_timer_;
    };

次に、クラスとスレッドを次のようにインスタンス化します。

    udp_server *udp_server_ptr=NULL;
    boost::asio::deadline_timer* dlineTimer=NULL;
    static void PluginInit_PostLoadCallback()
    {   
        _MESSAGE("NetworkPipe: PluginInit_PostLoadCallback called");

        if(!g_Interface->isEditor)
        {
            _MESSAGE("NetworkPipe: Starting UDP");
            udp_server_ptr = new udp_server(io_service, current_port);
            //dlineTimer = new boost::asio::deadline_timer(io_service);
            udp_thread = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service));         
            //
            _MESSAGE("NetworkPipe: UDP Started");
            NetworkPipeEnable = true;
        }
        else
        {
            _MESSAGE("NetworkPipe: Running in editor, not starting UDP");
        }    
    }

上記で dlineTimer がコメントアウトされていることに注意してください。それを有効にすると、機能しなくなります。この io サービスで dlineTimer を機能させる唯一の方法は、udp_server::handle_receive_from呼び出し中に作成することです。これは、他のスレッド内で実行されているためだと思います。そのため、何らかの理由で、deadline_timerオブジェクトは内部で実行する必要があるスレッドの外部で作成されることを好みません。

ここで、メイン スレッドと通信するために、concurrent_queueオブジェクトを使用します。したがって、これらを使用すると、スレッドの内外でメッセージを非常に簡単に送信できます。理論的にはdlineTimer、独自のスレッド内で実行し、出力キューを使用してそのアクティビティを管理できます。ただし、 と同じスレッドにあるというシンプルさが気に入っていudp_serverます。たとえば、udp_serverオブジェクトはクライアントをベクトルで追跡します。のdeadline_timer有効期限が切れると、既知のクライアントを循環してメッセージを送信します。次に、タイマーを再起動します。これにより、サーバーに送信される udp パケットから応答が独立します。そのため、パケットが到着すると、プロセスの別の部分のキューに入れられます。その後、データは出力待ち行列に置かれ、deadline_timerこれらの応答を処理し、適切なクライアントに送信します。

だから私の主な質問は:

deadline_timerオブジェクトと同じスレッドと同じものを使用して、オブジェクトをio_serviceよりきれいに作成するにはどうすればよいudp_serverですか?

4

1 に答える 1

0

さて、私はこれについて本当にばかげて考えていました。

  • 最初に、deadline_timer は、時間をかけたいスレッド内に完全に配置する必要があります。つまり、スレッド内に作成する必要があります。
  • 次に、スレッド ループで呼び出される関数を定義し、io_service::run 関数に設定しないようにする必要があります。そこで、udp_server::start 関数にしました。start 呼び出し内で、deadline_timer を作成します。

だからここにクラスがあります:

    class udp_server
    {
    public:
        udp_server(boost::asio::io_service& io_service, short port)
            : io_service_(io_service),
              socket_(io_service_, udp::endpoint(boost::asio::ip::address_v4::from_string(current_address), port))//, // udp::v4()  
        {
            // start udp receive
            socket_.async_receive_from(
                boost::asio::buffer(recv_buf), sender_endpoint_,
                boost::bind(&udp_server::handle_receive_from, this,
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred));  

            send_timer_ = NULL;            
        }

        ~udp_server(){
            io_service_.stop();
            if(send_timer_){
                send_timer_->cancel();
                delete send_timer_;
            }
        }

        void start();

        void startSendTimer();

        void handle_send_to(const boost::system::error_code& error, size_t bytes_recvd);
        void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd);

        void handle_send_timer();
        void send_timer_restart();

        void stop()
        {
            io_service_.stop();
        }

        private:
            boost::asio::io_service& io_service_;
            udp::socket socket_;
            udp::endpoint sender_endpoint_; 
            std::vector<udp::endpoint> clientList;               
            udp_buffer recv_buf;
            boost::asio::deadline_timer* send_timer_;                
    };

関連する関数は次のとおりです。

    void udp_server::start(){
        // startup timer
        startSendTimer();

        // run ioservice
        io_service_.run();
    }

    void udp_server::startSendTimer(){            
        // start send timer 
        if(!send_timer_)
            send_timer_ = new boost::asio::deadline_timer(io_service_, boost::posix_time::milliseconds(500));
        send_timer_restart();
    }

    void udp_server::send_timer_restart(){    
        if(send_timer_){
            // restart send timer
            send_timer_->expires_from_now(boost::posix_time::milliseconds(500));
            send_timer_->async_wait(boost::bind(&udp_server::handle_send_timer, this));
        }
    }        

    void udp_server::handle_send_timer(){            
        for(std::vector<udp::endpoint>::iterator itr = clientList.begin(); itr != clientList.end(); ++itr){
            socket_.async_send_to(
                boost::asio::buffer("heart beat", strlen("heart beat")), *itr,              
                boost::bind(&udp_server::handle_send_to, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
        }

        send_timer_restart(); 
    }

ですから、そもそもこれはすべて間違っていると考えていました。スレッドが実行を開始する開始点を定義する必要があります。スレッド内のスレッドに存在する必要があるオブジェクトを作成できます。

udp_server は次のように開始されます。

    static void PluginInit_PostLoadCallback()
    {   
        _MESSAGE("NetworkPipe: PluginInit_PostLoadCallback called");

        if(!g_Interface->isEditor)
        {
            _MESSAGE("NetworkPipe: Starting UDP");
            udp_server_ptr = new udp_server(io_service, current_port);                 
            udp_thread = new boost::thread(boost::bind(&udp_server::start, udp_server_ptr));         
            _MESSAGE("NetworkPipe: UDP Started");
            NetworkPipeEnable = true;
        }
        else
        {
            _MESSAGE("NetworkPipe: Running in editor, not starting UDP");
        }    
    }

現在、deadline_timer の作成は udp_thread 内で行われています。メインスレッドでdeadline_timerオブジェクトを作成すると、プログラムが正しくロードされませんでした。

于 2013-03-20T03:40:40.697 に答える