Асинхронный сервер
This commit is contained in:
parent
24942270f7
commit
aa93763bb4
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Ссылка на 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue