5

永久に実行され、リクエストを処理するサーバーには、データベースクエリを実行し、新しい変更があった場合にのみ更新するコードの非同期部分が必要です。サーバーは永久に実行する必要があり、db関数を繰り返し実行するためのこの関数は非同期で実行する必要があるため、「x」分ごとに1回更新されるため、サーバーに支障をきたすことはありません。

これをC++で非同期的に処理するにはどうすればよいでしょうか。サーバーをまったくブロックしないように、その関数をデーモンで実行するように単独で設定するにはどうすればよいですか?

4

3 に答える 3

5

BoostのASIOライブラリを使用することを強くお勧めします

新しいリクエストを受け入れるクラスと、定期的に更新をチェックするクラスが必要です。どちらも非同期で作業を行い、同じboost :: asio::io_serviceを使用して作業をスケジュールできます。

セットアップは

  • boost::asio::ip::tcp::acceptor新しいリクエストを非同期でリッスンするネットワーク。
  • boost::asio::deadline_time非同期待機を実行して、データベースの更新を確認します。

あなたが説明していると私が理解しているものの擬似コードは以下のとおりです。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <string>

class DatabaseUpdateChecker{
    public:
    DatabaseUpdateChecker(boost::asio::io_service& io, const int& sleepTimeSeconds)
    :timer_(io,boost::posix_time::seconds(sleepTimeSeconds)),sleepSeconds_(sleepTimeSeconds){
        this->timer_.async_wait(boost::bind(&DatabaseUpdateChecker::doDBUpdateCheck,this,boost::asio::placeholders::error));
    };

    protected:
    void doDBUpdateCheck(const boost::system::error_code& error){
        if(!error){
            std::cout << " Checking Database for updates" << std::endl;
            //Reschdule ourself
            this->timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(this->sleepSeconds_));
            this->timer_.async_wait(boost::bind(&DatabaseUpdateChecker::doDBUpdateCheck,this,boost::asio::placeholders::error));
        }
    };
    private:
    boost::asio::deadline_timer timer_;
    int sleepSeconds_;  
};

typedef boost::shared_ptr<boost::asio::ip::tcp::socket> TcpSocketPtr;

class NetworkRequest{
    public: 
    NetworkRequest(boost::asio::io_service& io, const int& port)
    :acceptor_(io,boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),port)){
        this->start_accept();   
    };  
    protected:
    void start_accept(){
        TcpSocketPtr socketPtr(new boost::asio::ip::tcp::socket(acceptor_.get_io_service()));
        std::cout << "About to accept new connection" << std::endl;
        acceptor_.async_accept(*socketPtr,boost::bind(&NetworkRequest::handle_accept,this,socketPtr,boost::asio::placeholders::error));
    };  
    void handle_accept(TcpSocketPtr socketPtr,const boost::system::error_code& error){
        std::cout << "Accepted new network connection" << std::endl;
        if(!error){
            std::string response("This is a response\n");
            boost::asio::async_write(*socketPtr,boost::asio::buffer(response),
                boost::bind(&NetworkRequest::handle_write,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
        }
        //Start listeing for a new connection
        this->start_accept();
    }   
    void handle_write(const boost::system::error_code& error,size_t size){
        if(!error){
            std::cout << "Wrote out " << size << " bytes to the network connection" << std::endl;
        }

    }   
    private:
    boost::asio::ip::tcp::acceptor acceptor_;
};

int main(int argc, char *argv[]) {
    static const int DB_TIMER_SECONDS=5;
    static const int LISTENING_TCP_PORT=4444;

    std::cout << "About to start" << std::endl;
    boost::asio::io_service io;

    DatabaseUpdateChecker dbChecker(io,DB_TIMER_SECONDS);
    NetworkRequest networkRequestAcceptor(io,LISTENING_TCP_PORT);

    io.run();

    std::cout << "This won't be printed" << std::endl;  
    return 0;
}

上記をコンパイルして実行すると、データベース更新チェッカーがTCPポート4444での接続をリッスンしている間、5秒ごとに更新をチェックすることが示されます。コードが新しい接続を受け入れることを確認するには、telnet /netcat/お気に入りのネットワーククライアントツールを使用できます。 ..。。

telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
This is a response
Connection closed by foreign host.

更新やリクエストの処理にかなりの時間がかかることがわかった場合は、アプリケーションをスレッド化し、各タスクを独自のスレッドで実行することを検討します。io_serviceは、実行する必要のある作業をスケジュールし、作業がなくなるまで完了しません。秘訣は、作業を行っているクラスが完了したら、自分でスケジュールを変更することです。

もちろん、あなたはあなたの質問に対する他の人のコメントを考慮に入れなければなりません。CORBAインターフェイスがこれをどのように複雑にするかはわかりませんが、非同期C++ライブラリとしてのboost:: asioは適切な決定であり、説明する内容に対して十分な柔軟性があると思います。

于 2011-12-16T15:54:41.520 に答える
1

システムがネットワーク要求を継続的に処理している間、DBと非同期で通信するという意味のように聞こえます。

つまり、DBと通信する必要がある場合、クエリを送信しますが、応答を待機しません。

DBから応答を受け取ると、それを処理します。

非同期部分は、DBと通信する別のスレッドを用意することで実装でき、応答を受け取ると、処理のためにサーバーキューに偶数を投稿します。

または、サーバーが多くのソケットでデータをリッスンしている可能性があり、そのうちの1つは、DBから応答を取得するデータベース接続である可能性があります。

于 2011-12-15T23:52:13.500 に答える
1

したがって、基本的に(私があなたを正しく理解している場合)、データベースが変更されているかどうかを確認するために定期的にデータベースをポーリングする必要があります。また、変更があった場合は、CORBAベースのリクエストプロセッサに変更があったことを通知する必要があります。

私がすることは、CORBAサーバーに新しいリクエストタイプを追加することです。リクエストは「データベースが更新されました。」になります。次に、データベースをポーリングし、データベースが更新されたときにCORBA要求を送信するだけの、小さな完全に異なるプログラムを作成できます。

このようにして、データベース更新メッセージをCORBAサーバーのメイン要求ストリームに折りたたむことができます。

スレッドも非同期もありません。それぞれが独自のことを行う2つのプロセスだけです。

于 2011-12-16T01:43:01.890 に答える