From aa93763bb4dea07001ccb52afafcc19baeb9fb9f Mon Sep 17 00:00:00 2001 From: Alexander Zhirov Date: Thu, 8 Sep 2022 10:31:37 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D1=81=D0=B8=D0=BD=D1=85=D1=80=D0=BE?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lesson_04/main.cpp | 134 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 lesson_04/main.cpp diff --git a/lesson_04/main.cpp b/lesson_04/main.cpp new file mode 100644 index 0000000..846194d --- /dev/null +++ b/lesson_04/main.cpp @@ -0,0 +1,134 @@ +/* + * Ссылка на boost урок: + * https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/tutorial.html + */ + +#include +#include +#include +#include +#include +#include +#include + +using boost::asio::ip::tcp; +const int echo_port = 1300; + +std::string make_daytime_string() +{ + using namespace std; + // time_t, time и ctime; + time_t now = time(0); + return ctime(&now); +} + +// Указатель shared_ptr и enable_shared_from_this нужны для того, +// чтобы сохранить объект tcp_connection до завершения выполнения операции. +class TcpConnection: public std::enable_shared_from_this +{ +public: + typedef std::shared_ptr pointer; + + static pointer create(boost::asio::io_context &io_context) + { + return pointer(new TcpConnection(io_context)); + } + + tcp::socket& socket() + { + return socket_; + } + + // В методе start(), вызывается asio::async_write(), отправляющий данные клиенту. + // Здесь используется asio::async_write(), вместо ip::tcp::socket::async_write_some(), чтобы весь блок данных был гарантированно отправлен. + void start() + { + // The data to be sent is stored in the class member message_ as we need to keep the data valid until the asynchronous operation is complete. + message_ = make_daytime_string(); + auto s = shared_from_this(); + + // Здесь вместо boost::bind используется std::bind, чтобы уменьшить число зависимостей от Boost. + // Он не работает с плейсхолдерами из Boost. + // В комментариях указаны альтернативные плейсхолдеры. + boost::asio::async_write(socket_, boost::asio::buffer(message_), + // handle_write() выполнит обработку запроса клиента. + [s](const boost::system::error_code &error, size_t bytes_transferred) + { + s->handle_write(error, bytes_transferred); + } + ); + } + +private: + TcpConnection(boost::asio::io_context &io_context) : socket_(io_context) + { + } + + void handle_write(const boost::system::error_code& /*error*/, size_t bytes_transferred) + { + std::cout << "Bytes transferred: " << bytes_transferred << std::endl; + } + +private: + tcp::socket socket_; + std::string message_; +}; + +class TcpServer +{ +public: + // В конструкторе инициализируется акцептор, начинается прослушивание TCP порта. + TcpServer(boost::asio::io_context &io_context) : io_context_(io_context), acceptor_(io_context, tcp::endpoint(tcp::v4(), echo_port)) + { + start_accept(); + } + +private: + // Метод start_accept() создаёт сокет и выполняет асинхронный `accept()`, при соединении. + void start_accept() + { + TcpConnection::pointer new_connection = TcpConnection::create(io_context_); + + acceptor_.async_accept(new_connection->socket(), [this, new_connection](const boost::system::error_code &error) + { + this->handle_accept(new_connection, error); + } + ); + } + + // Метод handle_accept() вызывается, когда асинхронный accept, инициированный в start_accept() завершается. + // Она выполняет обработку запроса клиента и запуск нового акцептора. + void handle_accept(TcpConnection::pointer new_connection, const boost::system::error_code &error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + +private: + boost::asio::io_context &io_context_; + tcp::acceptor acceptor_; +}; + +int main() +{ + try + { + // io_context предоставляет службы ввода-вывода, которые будет использовать сервер, такие как сокеты. + boost::asio::io_context io_context; + TcpServer server(io_context); + + // Запуск асинхронных операций. + io_context.run(); + } + catch (const std::exception &e) + { + std::cerr << e.what() << std::endl; + } + + return EXIT_SUCCESS; +} +