Несколько Http-серверов с Poco и Boost C++

Я пытаюсь создать несколько серверов Http с библиотеками Poco::Net и Boost, но внутри 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 предназначен для асинхронного вызова метода exec, а конструкция service(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

Ошибка отображается при запуске второго сервера.

1 ответ

Решение

HttpServerApplication не предназначен для использования таким образом. Он предназначен для одного человека.

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

Вы можете исправить эту часть, не производя от ServerApplication в вашем HttpServer учебный класс. В конце концов, вам нужно несколько серверов, а не приложений.

В моем простейшем тесте работает следующее:

#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 по единственной причине использования защищенного метода 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 объект, прежде чем использовать его в любом потоке.

Другие вопросы по тегам