Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ_ИКТ Программирование по С++ (1 семестр) _Хотов.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
5.83 Mб
Скачать
    1. Boost::asio (::io_service) (Самостоятельное изучение) boost::asio основы

boost::asio на самом деле, хоть и называется библиотекой асинхронной, но может выполнять и синхронные, и асинхронные операции. Вся библиотека при этом завязана на объекты класса boost::asio::io_service – именно asio::io_service предоставляет программе связь с нативными объектами ввода/вывода. Соответственно, что бы ваша программа могла работать с boost::asio, нужно создать хотя бы один объект этого класса и уже после этого “аттачить” все другие объекты к нему, например вот так:

boost::asio::io_service io_service;

boost::asio::ip::tcp::socket socket(io_service);

Подключить только что созданный сокет к серверу тоже не представляет из себя проблемы:

boost::system::error_code ec; // здесь будет записана ошибка, если она была

socket.connect(server_endpoint, ec); // server_endpoint задаёт куда подключаемся

После того как мы подключили объекты ввода-вывода (в данном случае socket) к asio::io_service – этот сервис будет осуществлять взаимодействие с операционной системой и получать/отправлять данные.

Boost::asio асинхронный

Тот вариант, что мы рассмотрели выше – это синхронное взаимодействие, т.е., в данном случае это значит, что пока происходит подключение – наша программа “зависнет” до того момента, пока подключение не выполнится, либо не произойдёт ошибка. Если же мы хотим что бы работа boost::asio была асинхронной, надо идти немного другим путём, который тоже предусмотрен в библиотеке. Для работы с асинхронными операциями мы должны передать в функцию так называемый completion handler, или, говоря по русски, функцию, которая будет вызвана, когда операция завершится (т.е. либо подключится, либо возникнет ошибка):

void your_completion_handler(const boost::system::error_code& ec)

{

// тут обрабатываем подключение либо ошибку

}

boost::asio::io_service io_service;

boost::asio::ip::tcp::socket socket(io_service);

socket.async_connect(server_endpoint, your_completion_handler);

Все асинхронные функции в boost::asio работают именно по такому принципу. С одной стороны, это довольно удобно для программирования – логика работы каждой из функций отделена от других, с другой стороны это может может показаться Вам немного непривычным. Но, я уверен, Вы освоитесь

Использование boost::asio

Приведу короткий и простой пример использования boost::asio , это код примера из самого boost, лишь перевёл комментарии:

#include <iostream>

#include <istream>

#include <ostream>

#include <string>

#include <boost/asio.hpp>

using boost::asio::ip::tcp;

int main(int argc, char* argv[])

{

try

{

if (argc != 3) // если аргументы не заданы или заданы не все

{

std::cout << "Usage: sync_client <server> <path>\n";

std::cout << "Example:\n";

std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n";

return 1;

}

boost::asio::io_service io_service; // основной класс asio

// Получаем список конечных точек для указанного сервера

tcp::resolver resolver(io_service);

tcp::resolver::query query(argv[1], "http");

tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

tcp::resolver::iterator end;

// Перебираем эти конечные точки и пробуем подключиться

tcp::socket socket(io_service);

boost::system::error_code error = boost::asio::error::host_not_found;

while (error && endpoint_iterator != end)

{

socket.close();

socket.connect(*endpoint_iterator++, error);

}

if (error) // подключиться не удалось

throw boost::system::system_error(error);

// Формируем запрос к веб-серверу. Указываем "Connection: close" что бы

// сервер закрыл соединение как только отправит нам данные. Это

// позволит нам узнать что отправка завершенна как только возникнет EOF

boost::asio::streambuf request;

std::ostream request_stream(&request);

request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";

request_stream << "Host: " << argv[1] << "\r\n";

request_stream << "Accept: */*\r\n";

request_stream << "Connection: close\r\n\r\n";

// Отправляем сформированный запрос веб-серверу.

boost::asio::write(socket, request);

// Читаем ответ сервер. streambuf response примет все данные

// он сам будет увеличиваться по мере поступления данных от сервера.

boost::asio::streambuf response;

boost::asio::read_until(socket, response, "\r\n");

// Проверяем что бы не было ошибок.

std::istream response_stream(&response);

std::string http_version;

response_stream >> http_version;

unsigned int status_code;

response_stream >> status_code;

std::string status_message;

std::getline(response_stream, status_message);

if (!response_stream || http_version.substr(0, 5) != "HTTP/") // ошибка

{

std::cout << "Invalid response\n";

return 1;

}

if (status_code != 200) // если код ответа не 200, то это тоже ошибка

{

std::cout << "Response returned with status code " << status_code << "\n";

return 1;

}

// Читаем ответ. Он закончится пустой строкой.

boost::asio::read_until(socket, response, "\r\n\r\n");

// Парсим заголовки

std::string header;

while (std::getline(response_stream, header) && header != "\r")

std::cout << header << "\n";

std::cout << "\n";

// Выводим в лог

if (response.size() > 0)

std::cout << &response;

// Теперь читаем до конца

while (boost::asio::read(socket, response,

boost::asio::transfer_at_least(1), error))

std::cout << &response;

if (error != boost::asio::error::eof) // ошибка

throw boost::system::system_error(error);

}

catch (std::exception& e) // возникло исключение

{

std::cout << "Exception: " << e.what() << "\n";

}

return 0;

}

Вот эти 100 строк кода работают как HTTP-клиент и позволяют нам читать страницы с веб-серверов. Мне кажется, что код не сложный, особенно, когда он с комментариями.