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