The
Pion Network Library is a great library to add a web server to your application. Sadly it is not very documented and it is sometimes hard to find how to do some really simple things.
Here is an example on how to create a simple web server.
The class containing our web server will have a really simple interface :
using namespace pion::net; // to simplify the example syntax, REMOVE IN REAL CODE.
class WebServer
{
public:
/**
* Start the web server
* @param _port the port to listen on.
*/
void start(unsigned int _port);
/**
* Stop the web server.
*/
void stop();
private:
/**
* Handle http requests.
* @param _httpRequest the request
* @param _tcpConn the connection
*/
void requestHandler(HTTPRequestPtr& _httpRequest, TCPConnectionPtr& _tcpConn)
pion::net::HTTPServerPtr m_httpServer;
};
The only two public method of our web server are the start and stop method that will, as everybody expect, start and stop the server. The web server also define a private method that will be used as the web server request callback.
Let's continue with the real
Pion Network Library code, the implementation of the start and stop methods:
/**
* Start the web server
* @param _port the port to listen on.
*/
void WebServer::start(unsigned int _port)
{
// Create a web server and specify the port on witch it will listen.
m_httpServer = pion::net::HTTPServerPtr(
new pion::net::HTTPServer(_port));
// Add a resource.
m_httpServer->addResource("/",
boost::bind(&WebServer::requestHandler, this, _1, _2));
// Start the web server.
m_httpServer->start();
}
/**
* Stop the web server.
*/
void WebServer::stop()
{
// Just check that the http server has been created before stopping it.
if (m_httpServer.get() != NULL)
{
m_httpServer->stop();
}
}
Once again the code is really simple. The most interesting part here is the addition of the resource. It will defined the callback executed when a client send a request on the given page.
Here "/" is the root resource and will correspond to "http://server_ip:_port/". Every time a client will make a request to this resource the WebServer::requestHandler will be executed.
The only subtlety is the use of the boost::bind function to call the web server instance method and not a static or global function. The boost::bind will call the method with two arguments _1 and _2 that correspond to the request and the tcp connection defined in the requestHandler method and with a pointer to this instance that is hidden in every instance method.
The only thing left is to write the request handler method :
/**
* Handle http requests.
* @param _httpRequest the request
* @param _tcpConn the connection
*/
void WebServer::requestHandler(HTTPRequestPtr& _httpRequest, TCPConnectionPtr& _tcpConn)
{
static const std::string kHTMLStart("<html><body>\n");
static const std::string kHTMLEnd("</body></html>\n");
HTTPResponseWriterPtr writer(
HTTPResponseWriter::create(
_tcpConn,
*_httpRequest,
boost::bind(&TCPConnection::finish, _tcpConn)));
HTTPResponse& r = writer->getResponse();
HTTPTypes::QueryParams& params =
_httpRequest->getQueryParams();
writer->writeNoCopy(kHTMLStart);
HTTPTypes::QueryParams::const_iterator paramIter = params.find("id");
if (paramIter != params.end())
{
r.setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_OK);
r.setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_OK);
std::string id = paramIter->second;
writer->write("Request id : ");
writer->write(id);
}
else
{
r.setStatusCode(pion::net::HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
r.setStatusMessage(pion::net::HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
}
writer->writeNoCopy(kHTMLEnd);
writer->send();
}
This method search for the id parameter in the parameter list and write it back on the response. Of course this is not very useful and you should add your application logic instead of this method. It is for example possible to look for certain parameters and send them back to another method (eventually with the boost::bind mechanism) that will do the real real logic.
To test this example you can use the following main function:
int main()
{
WebServer server;
server.start(12345);
while (1)
{
sleep(5000);
}
return 0;
}