5

将永远运行并处理请求的服务器需要其中的异步代码部分,该代码将执行一些数据库查询并仅在对其进行任何新更改时才更新。服务器必须永远运行,并且这个用于一次又一次执行 db 函数的函数必须异步运行,这样就不会因为每“x”分钟更新一次而妨碍服务器。

在 c++ 中如何最好地异步处理它?如何单独设置该功能以在守护程序上运行,以便它根本不会阻塞服务器?

4

3 回答 3

5

我强烈推荐使用Boost 的ASIO 库

您需要一个类来接受新请求,另一个类来定期检查更新。两者都可以异步完成工作,并使用相同的 boost::asio::io_service 来安排工作。

设置将是

  • 网络异步boost::asio::ip::tcp::acceptor监听新请求。
  • Aboost::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 接口如何使这复杂化,但我认为 boost::asio 作为异步 C++ 库将是一个很好的决定,并且对于您所描述的内容足够灵活。

于 2011-12-16T15:54:41.520 回答
1

听起来这意味着当系统连续处理网络请求时,它与数据库异步通信。

这意味着当它需要与 DB 通信时,它会发送查询但不等待响应。

当它从数据库获得响应时,它会处理它。

异步部分可以通过有一个单独的线程与 DB 对话来实现,当它得到响应时,它会在服务器队列中发布一个偶数以进行处理。

或者服务器可能正在许多套接字上侦听数据,其中一个可能是从数据库获取响应的数据库连接。

于 2011-12-15T23:52:13.500 回答
1

所以基本上(如果我理解正确的话)你需要定期轮询数据库以查看它是否已更改。当它发生变化时,您需要通知基于 CORBA 的请求处理器发生了变化。

我要做的是向您的 CORBA 服务器添加一个新的请求类型。请求将是“数据库已更新。”。然后,您可以编写一个完全不同的小型程序,该程序的唯一工作是轮询数据库并在数据库更新时发送 CORBA 请求。

这样,您可以将数据库更新消息折叠到 CORBA 服务器的主请求流中。

没有线程,没有任何异步的东西。只有两个进程各自做自己的事情。

于 2011-12-16T01:43:01.890 回答