Thread: Server<T> good approach?

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    40

    Server<T> good approach?

    Hi all,
    I am trying to figure out a good way to implement a Server class which would not be to hard to reuse and I come up with this:

    Server
    Code:
    template <typename Handler>
    class Server
    {
    public:
    //....
    private:
    //...
    Handler & m_handler;
    };
    There the Handler requires to have two methods:

    void init(Server<Handler>&) throw();
    void newConnection(boost::asio::ip::tcp::socket*);

    But I wonder, is this really a good approach?

    If someone didn't exactly understood me so here comes a example:

    Server.hpp
    Code:
    #ifndef H_HEADER_SERVER_H
    #define H_HEADER_SERVER_H
    
    #include <boost/thread.hpp>
    #include <boost/asio.hpp>
    #include <string>
    #include <boost/bind.hpp>
    #include <boost/unordered_set.hpp> //delete if not used
    #include <iostream>
    
    
    namespace details
    {
    	template <typename T>
    	class IsRunning
    	{
    	private:
    		T & var;
    	public:
    		IsRunning(T & a)
    			: var(a)
    		{
    			var = true;
    		}
    		~IsRunning()
    		{
    			var = false;
    		}
    	};
    
    	class ServiceInvoker
    	{
    	private:
    		boost::asio::io_service & service;
    	public:
    		ServiceInvoker(boost::asio::io_service &);
    		void run();
    	};
    	
    	ServiceInvoker::ServiceInvoker(boost::asio::io_service & ser)
    		: service(ser)
    	{
    	}
    
    	
    	void ServiceInvoker::run()
    	{
    		while(true)
    		{
    			try
    			{
    				service.run();
    				break;
    			}
    			catch(std::exception & exception)
    			{
    				std::cerr << "Exception catched:\n" << exception.what() << "\n"; // may add more error handling here later
    			}
    			catch(...)
    			{
    				std::cerr << "Unkown exception catched\n"; // may add more error handling here later
    			}
    		}
    	}
    }
    /*
    Handler most have the follow methods:
    
    void init(Server<Handler>&) throw();
    	The server constructor will invoke this method
    
    void newConnection(boost::asio::ip::tcp::socket*);
    	Every incoming connection will be passed to this method.
    	The method most then delete the pointer because the Server will not.
    
    */
    template <typename Handler>
    class Server
    {
    public:
    	Server(Handler &, boost::asio::io_service &);
    	~Server();
    	/* set the io_service object */
    	bool setPort(unsigned short int);
    	unsigned short int getPort() const;
    
    	bool setAddress(const std::string &, const std::string &);
    	std::string getAddress() const;
    
    	bool setPoolsize(unsigned);
    	unsigned getPoolsize() const;
    
    	boost::asio::io_service & getService();
    	const boost::asio::io_service & getService() const;
    
    	boost::asio::ip::tcp::acceptor & getAcceptor();
    	const boost::asio::ip::tcp::acceptor & getAcceptor() const;
    
    	bool isRunning() const;
    	void stop();
    	void stopListen();
    	bool isListen();
    	void startListen();
    	void startAccept();
    	bool isAccept();
    	void stopAccept();
    	void secureStop();
    	void run();
    private:
    	void handle_accept(const boost::system::error_code& e);
    
    	std::size_t m_pool_size;
    	bool m_accept;
    	bool m_is_running;
    	boost::asio::ip::tcp::acceptor m_acceptor;
    	boost::asio::ip::tcp::socket* m_next_socket;	
    	boost::asio::io_service & m_io_service;
    	Handler & m_handler;
    };
    
    
    template <typename Handler>
    Server<Handler>::Server(Handler & handler, boost::asio::io_service & service)
    	: m_acceptor(service), m_next_socket(new boost::asio::ip::tcp::socket(service)),
            m_io_service(service), m_handler(handler), m_accept(false), m_is_running(false), 
           m_pool_size(boost::thread::hardware_concurrency())
    {
    	m_handler.init(*this);
    }
    
    template <typename Handler>
    Server<Handler>::~Server()
    {
    	delete m_next_socket;
    }
    
    template <typename Handler>
    bool Server<Handler>::setPort(unsigned short int p)
    {
    	if(isRunning())
    	{
    		return false;
    	}
    	m_acceptor.local_endpoint().port(p);
    	return true;
    }
    
    template <typename Handler>
    unsigned short int Server<Handler>::getPort() const
    {
    	return m_acceptor.local_endpoint().port();
    }
    template <typename Handler>
    bool Server<Handler>::setAddress(const std::string & address, const std::string &port)
    {
    	if(isRunning())
    	{
    		return false;
    	}
    	boost::asio::ip::tcp::resolver resolver(m_io_service);
    	boost::asio::ip::tcp::resolver::query query(address, port);
    	boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
    	
    	m_acceptor.open(endpoint.protocol());
    	m_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); // try without this later
    	m_acceptor.bind(endpoint);
    	return true;
    }
    template <typename Handler>
    std::string Server<Handler>::getAddress() const
    {
    	return m_acceptor.local_endpoint().address().to_string();
    }
    template <typename Handler>
    bool Server<Handler>::setPoolsize(unsigned size)
    {
    	if(isRunning())
    	{
    		return false;
    	}
    	m_pool_size = size;
    	return true;
    }
    template <typename Handler>
    unsigned Server<Handler>::getPoolsize() const
    {
    	return m_pool_size;
    }
    
    template <typename Handler>
    boost::asio::io_service & Server<Handler>::getService()
    {
    	return m_io_service;
    }
    template <typename Handler>
    const boost::asio::io_service & Server<Handler>::getService() const
    {
    	return m_io_service;
    }
    template <typename Handler>
    boost::asio::ip::tcp::acceptor & Server<Handler>::getAcceptor()
    {
    	return m_acceptor;
    }
    template <typename Handler>
    const boost::asio::ip::tcp::acceptor & Server<Handler>::getAcceptor() const
    {
    	return m_acceptor;
    }
    template <typename Handler>
    bool Server<Handler>::isRunning() const
    {
    	return m_is_running;
    }
    template <typename Handler>
    void Server<Handler>::stop()
    {
    	m_io_service.stop();
    }
    template <typename Handler>
    void Server<Handler>::stopListen()
    {
    	m_acceptor.close();
    }
    template <typename Handler>
    bool Server<Handler>::isListen()
    {
    	m_acceptor.is_open();
    }
    template <typename Handler>
    void Server<Handler>::startListen()
    {
    	m_acceptor.listen();
    }
    
    template <typename Handler>
    void Server<Handler>::startAccept()
    {
    	m_accept = true;
    	m_acceptor.async_accept(*m_next_socket,
    	  boost::bind(&Server::handle_accept, this,
    		boost::asio::placeholders::error));
    }
    template <typename Handler>
    void Server<Handler>::secureStop()
    {
    	stopListen(); // should maybe be stopAccept(); instead
    	while(isRunning())
    	{
    		boost::thread::yield();
    	}
    }
    
    template <typename Handler>
    void Server<Handler>::run()
    {
    	details::IsRunning<bool> isrunning(this->m_is_running);
    	
    	startListen();
    	startAccept();
    	details::ServiceInvoker invoker(this->m_io_service);
    	std::vector<boost::shared_ptr<boost::thread> > threads;
    	threads.reserve(m_pool_size-1);
    	// the serviceinvoker class make sure the io_service will be invoked again if the io_service cast an exception
    	for(int i = 0; i < m_pool_size-1; i++)
    	{
    		threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&details::ServiceInvoker::run, &invoker))));
    	}
    	invoker.run();
    	for (std::size_t i = 0; i < threads.size(); ++i)
    	{
    		threads[i]->join();
    	}
    	return;
    }
    
    template <typename Handler>
    void Server<Handler>::handle_accept(const boost::system::error_code& error)
    {
    	if(error)
    	{
    		return;
    	}
    	m_handler.newConnection(m_next_socket);
    	
    	m_next_socket = new boost::asio::ip::tcp::socket(this->m_acceptor.io_service());
    	if(m_accept)
    	{
    		m_acceptor.async_accept(*m_next_socket,
    			boost::bind(&Server::handle_accept, this,
    			  boost::asio::placeholders::error));
    	}
    	
    }
    
    #endif
    main.cpp
    Code:
    #include "server.hpp"
    #include <iostream>
    
    
    class ConnectionHandler
    {
    public:
    	void init(Server<ConnectionHandler> & server)
    	{
    		std::cout << "Initialized" << std::endl;
    		server.setAddress("localhost","9999");
    	}
    	void newConnection(boost::asio::ip::tcp::socket* p)
    	{
    		std::cout << "Connection..." << std::endl;
    		delete p;
    	}
    private:
    };
    
    
    
    int main(int argc, char* argv[])
    {
    	
    
    	try
    	{
    		const std::string host = "localhost";
    		const std::string port = "8219";
    		boost::asio::io_service io_service;
    
    		ConnectionHandler handler;
    		Server<ConnectionHandler> server(handler, io_service);
    		server.run();
    	}
    	catch (std::exception& e)
    	{
    		std::cerr << e.what() << std::endl;
    	}
    	std::cin.get();
    	return 0;
    }
    Mostly of the code did I wrote when I was tired so there is surely some logical bugs or something, but you get the point.


    Thanks in advance!
    Last edited by idleman; 07-18-2009 at 06:44 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. In a game Engine...
    By Shamino in forum Game Programming
    Replies: 28
    Last Post: 02-19-2006, 11:30 AM
  2. Good books for learning WIN32 API
    By Junior89 in forum Windows Programming
    Replies: 6
    Last Post: 01-05-2006, 05:38 PM
  3. Good resources for maths and electronics
    By nickname_changed in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 12-22-2004, 04:23 PM
  4. what is good for gaphics in dos
    By datainjector in forum Game Programming
    Replies: 2
    Last Post: 07-15-2002, 03:48 PM
  5. i need links to good windows tuts...
    By Jackmar in forum Windows Programming
    Replies: 3
    Last Post: 05-18-2002, 11:16 PM