C Board  

Go Back   C Board > General Programming Boards > Networking/Device Communication

Reply
 
LinkBack Thread Tools Display Modes
Old 07-18-2009, 06:41 AM   #1
Registered User
 
Join Date: Feb 2009
Posts: 32
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.
idleman is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

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


All times are GMT -6. The time now is 03:23 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22