使用Poco和Boost C++的多个Http服务器

Multiple Http Servers with Poco and Boost C++

本文关键字:Http 服务器 C++ Poco Boost 使用      更新时间:2023-10-16

我正试图用Poco::Net和Boost库创建多个Http服务器,但在Poco文件Application.cpp:内部出现以下错误

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Assertion violation: _pInstance == 0 [in file "src/Application.cpp", line 115]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

我正在使用以下代码:

#include <Poco/Net/HTMLForm.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <boost/asio/io_service.hpp>
boost::asio::io_service service(100);
class RequestHandler : public Poco::Net::HTTPRequestHandler {
public:
    RequestHandler(){}
    void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response){}
};
class RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
    RequestHandlerFactory(){}
    Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request)
    {
        return new RequestHandler();
    }
};
class HttpServer :
        public Poco::Util::ServerApplication,
        public boost::enable_shared_from_this<HttpServer>{
    Poco::Net::ServerSocket svs;
    Poco::Net::HTTPServer srv;
public:
    HttpServer(std::string address_, Poco::UInt16 port_):
        svs(Poco::Net::SocketAddress(address_.empty() ? "127.0.0.1" : address_, port_)),
        srv(new RequestHandlerFactory(), svs, new Poco::Net::HTTPServerParams)
    {
        svs.setReuseAddress(true);
        svs.setReusePort(true);
    }
    virtual ~HttpServer(){}
    void start()
    {
        service.post(
            boost::bind(&HttpServer::exec, shared_from_this()));
    }
    void stop()
    {
        srv.stop();
    }
private:
    void exec()
    {
        srv.start();
        waitForTerminationRequest();
        srv.stop();
    }    
};

这是服务器的主代码,例如,我在主功能中创建服务器。service.post调用用于异步调用方法execservice(100)的构造引用大小为100的线程池。

服务器创建如下:

boost::shared_ptr<HttpServer> server(
        new HttpServer("", 8080));
boost::shared_ptr<HttpServer> server2(
        new HttpServer("", 8181));
server->start();
server2->start(); // Error occurs here

第二台服务器启动时会显示错误。

HttpServerApplication并非设计用于这种方式。它被设计成一个单例。

http://pocoproject.org/docs/Poco.Util.ServerApplication.html

您可以通过不从HttpServer类中的ServerApplication派生来修复该部分。毕竟,您需要多个服务器,而不是应用程序。

在我最简单的测试中,以下方法有效:

#include <Poco/Net/HTMLForm.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPRequestHandlerFactory.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/HTTPServer.h>
#include <Poco/Util/ServerApplication.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
boost::asio::io_service service(100);
class RequestHandler : public Poco::Net::HTTPRequestHandler {
public:
    RequestHandler(){}
    void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response){}
};
class RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
    RequestHandlerFactory(){}
    Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request)
    {
        return new RequestHandler();
    }
};
class HttpServer : public boost::enable_shared_from_this<HttpServer>{
    Poco::Net::ServerSocket svs;
    Poco::Net::HTTPServer srv;
public:
    HttpServer(std::string address_, Poco::UInt16 port_):
        svs(Poco::Net::SocketAddress(address_.empty() ? "127.0.0.1" : address_, port_)),
        srv(new RequestHandlerFactory(), svs, new Poco::Net::HTTPServerParams)
    {
        svs.setReuseAddress(true);
        svs.setReusePort(true);
    }
    virtual ~HttpServer(){}
    void start()
    {
        service.post(
            boost::bind(&HttpServer::exec, shared_from_this()));
    }
    void stop()
    {
        srv.stop();
    }
private:
    void exec()
    {
        srv.start();
    }    
};

main中,我创建了ServerApplication的一个子类,唯一的原因是在退出main之前请求受保护的方法waitForTerminationRequest()。如果您需要参数解析,当然可以将argc, argv传递给app.run。但在这一点上,我认为没有必要。

int main() {
    struct App : Poco::Util::ServerApplication {
        ~App() {
            waitForTerminationRequest();
        }
    } app;
    for (int i=0; i<2; ++i) {
        boost::make_shared<HttpServer>("", 8080+i)->start();
    }
}

旧答案文本

您是如何实例化HttpServer对象的?

  1. 显然,应该使用boost::make_shared<HttpServer>(host, port)(或shared_ptr<HttpServer>(new HttpServer(host, port)))来允许使用enable_shared_from_this。不要忘记至少在服务启动之前保留共享ptr(通过将其exec()调用发布到io_service)。

    具体来说,这是非法的:

    for (int i=0; i<10; ++i) {
        HttpServer s("", 8080+i);
        s.start();
    }
    

    相反,使用例如

    for (int i=0; i<10; ++i) {
        boost::make_shared<HttpServer>("", 8080+i)->start();
    }
    
  2. 此外,如果要在100个线程的池中运行它,需要使用strand(用于执行的逻辑线程)在任何线程上使用HttpServer对象之前锁定它。

    • 为什么在使用boost::asio时,我需要每个连接一条绞线