I'm trying to create multiple Http servers with Poco::Net and Boost libraries, but is occurring the following error internally in Poco file Application.cpp:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Assertion violation: _pInstance == 0 [in file "src/Application.cpp", line 115]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I'm using the code below:
#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();
}
};
This is the main code of server, and Im creating the servers at main function for example.
The service.post call, is for asynchronous call of method exec and the construction of service(100) refers to a thread pool of size 100.
The server is created as follows:
boost::shared_ptr<HttpServer> server(
new HttpServer("", 8080));
boost::shared_ptr<HttpServer> server2(
new HttpServer("", 8181));
server->start();
server2->start(); // Error occurs here
The error is shown when the second server is started.
HttpServerApplication
is not designed to be used in this way. It's designed to be a singleton.
http://pocoproject.org/docs/Poco.Util.ServerApplication.html
You can fix that part by not deriving from ServerApplication
in your HttpServer
class. After all, you want multiple servers, not applications.
In my simplest test, the following works:
#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();
}
};
In main
, I create a subclass of ServerApplication
for the sole reason of claling the protected method waitForTerminationRequest()
before exit of main. If you need argument parsing, of course pass argc, argv
to app.run
. But at this point I don't see the need.
int main() {
struct App : Poco::Util::ServerApplication {
~App() {
waitForTerminationRequest();
}
} app;
for (int i=0; i<2; ++i) {
boost::make_shared<HttpServer>("", 8080+i)->start();
}
}
OLD ANSWER TEXT
How are you instantiating the HttpServer
objects?
You should, obviously, use boost::make_shared<HttpServer>(host, port)
(or shared_ptr<HttpServer>(new HttpServer(host, port))
) for enable_shared_from_this
to be allowed. Don't forget to hold on to the shared ptr at least until the service has been started (by posting it's exec()
call to io_service
).
Specifically, this is illegal:
for (int i=0; i<10; ++i) {
HttpServer s("", 8080+i);
s.start();
}
Instead, use e.g.
for (int i=0; i<10; ++i) {
boost::make_shared<HttpServer>("", 8080+i)->start();
}
Also, if you're going to run it on a pool of 100 threads, you need to either use a strand
(for a logical thread of execution) or lock the HttpServer
object before you use it on any thread.
- Why do I need strand per connection when using boost::asio?