Solution Challenge #1: SimpleServer API

Hello Everyone,

so, I’ve created an implementation for the challenge from last week, and it is split into two parts, the header and the cpp file:

simpleserver.h:

#ifndef _SIMPLESERVER_H_
#define _SIMPLESERVER_H_

#include <string>
#include <queue>
#include <memory>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>

class IConnection
{
  // Copy from Challenge ...
};
class IConnectionFactory
{
  // Copy from Challenge ...
};
class SimpleServerConnection : public boost::enable_shared_from_this<SimpleServerConnection>
{
	public:
		typedef boost::shared_ptr<SimpleServerConnection> pointer;
		SimpleServerConnection(boost::asio::io_service& io_service);
		boost::asio::ip::tcp::socket& socket();
		void setConnection(std::shared_ptr<IConnection> connection);
		void start();
		void write(const std::string &value);
	private:
		void do_read();
		void do_write();
		boost::asio::ip::tcp::socket m_socket;
		enum { max_length = 1024 };
		char m_data[max_length];
		std::shared_ptr<IConnection> m_connection;
		std::queue<std::string> m_fifo;

};

class SimpleServer
{
public:
	SimpleServer(int portno, IConnectionFactory *connection_factory);
	~SimpleServer();
	void run();
private:
	void handle_accept(SimpleServerConnection::pointer new_connection,
			const boost::system::error_code& error);
	void start_accept();
	std::shared_ptr<IConnectionFactory> m_factory;
	boost::asio::io_service m_io_service;
	boost::asio::ip::tcp::acceptor m_acceptor;
};

#endif /* _SIMPLESERVER_H_ */

simpleserver.cpp

#include "simpleserver.h"
#include <boost/asio/placeholders.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/read.hpp>
#include <boost/bind.hpp>



void SimpleServerConnection::do_read()
{
	auto self(shared_from_this());
	m_socket.async_read_some(boost::asio::buffer(m_data, max_length),
			[this, self](boost::system::error_code ec, std::size_t length)
			{
				if (!ec) {
					std::string tmp(m_data, length);
					m_connection->receive(tmp);
					do_read();
				}
			});
}

void SimpleServerConnection::do_write()
{
	std::string value = m_fifo.front();
	m_fifo.pop();
	size_t length = std::min((size_t)value.length(), (size_t)max_length);
	memcpy(m_data, value.data(), length);
	auto self(shared_from_this());
	boost::asio::async_write(m_socket, boost::asio::buffer(m_data, length),
			[this, self](boost::system::error_code ec, std::size_t)
			{
				if (!m_fifo.empty()) {
					do_write();
				}
			});
}

void SimpleServerConnection::setConnection(std::shared_ptr<IConnection> connection)
{
	m_connection = connection;
}

void SimpleServerConnection::start()
{
	do_read();
}

void SimpleServerConnection::write(const std::string &value)
{
	m_fifo.push(value);
	if (m_fifo.size() == 1) {
		do_write();
	}
}



SimpleServerConnection::SimpleServerConnection(boost::asio::io_service& io_service) :
	m_socket(io_service)
{
}

boost::asio::ip::tcp::socket& SimpleServerConnection::socket()
{
    return m_socket;
}

SimpleServer::SimpleServer(int portno, IConnectionFactory *connection_factory) :
	m_factory(std::shared_ptr<IConnectionFactory>(connection_factory)),
	m_acceptor(m_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), portno))
{
	start_accept();
}

SimpleServer::~SimpleServer()
{
}


void SimpleServer::handle_accept(SimpleServerConnection::pointer new_connection,
		const boost::system::error_code& error)
{
	if (!error) {
		std::shared_ptr<IConnection> c = std::shared_ptr<IConnection>(m_factory->create(
					boost::bind(&SimpleServerConnection::write, new_connection.get(), _1)));
		new_connection->setConnection(c);
		new_connection->start();
	}
	start_accept();
}

void SimpleServer::run()
{
	m_io_service.run();
}

void SimpleServer::start_accept()
{
	SimpleServerConnection::pointer new_connection = SimpleServerConnection::pointer(new SimpleServerConnection(m_io_service));
	m_acceptor.async_accept(new_connection->socket(),
			boost::bind(&SimpleServer::handle_accept, this, new_connection, boost::asio::placeholders::error));
}

Have fun,
-Richard

Advertisements

Leave a Reply, Keep it friendly, happy :-)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s