135 lines
4.5 KiB
C++
135 lines
4.5 KiB
C++
|
/*
|
|||
|
* Ссылка на boost урок:
|
|||
|
* https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/tutorial.html
|
|||
|
*/
|
|||
|
|
|||
|
#include <ctime>
|
|||
|
#include <functional>
|
|||
|
#include <iostream>
|
|||
|
#include <memory>
|
|||
|
#include <string>
|
|||
|
#include <boost/system/error_code.hpp>
|
|||
|
#include <boost/asio.hpp>
|
|||
|
|
|||
|
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<TcpConnection>
|
|||
|
{
|
|||
|
public:
|
|||
|
typedef std::shared_ptr<TcpConnection> 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;
|
|||
|
}
|
|||
|
|