Войти
ПрограммированиеФорумСеть

Boost asio для чайника

#0
13:00, 9 мая 2019

Здравствуйте,

Не судите пожалуйста строго, ни разу не работал с сетью:

Есть готовый рабочий пример запроса html страницы c помощью boost asio у сервера:

#include <iostream>
#include <fstream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
 
using boost::asio::ip::tcp;
 
int main()
{
    std::locale::global(std::locale(""));
    try
    {
        std::cout << "Enter URL(example: [url]www.cyberforum.ru):[/url] ";
        std::string URL;// = "www.cyberforum.ru";
        std::getline(std::cin, URL, '\n');
 
        boost::asio::io_service io_service;
 
        tcp::resolver resolver(io_service);
        tcp::resolver::query query(URL, "80");
        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);
 
        boost::asio::streambuf request;
        std::ostream request_stream(&request);
        request_stream << "GET / HTTP/1.0\r\n"
                       << "Host: " + URL + "\r\n"
                       << "Accept: text/html\r\n"
                       << "Connection: close\r\n\r\n";
 
        boost::asio::write(socket, request);
        boost::asio::streambuf response;
        boost::asio::read_until(socket, response, "\r\n");
 
        std::istream response_stream(&response);
        std::string header;
        while (std::getline(response_stream, header) && header != "\r");
        
        std::ofstream file("web_source.txt");
        if(!file)
            throw std::runtime_error("Cannot create file");
 
        while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error))
        {
            file << &response;
        }
        if (error != boost::asio::error::eof)
            throw boost::system::system_error(error);
 
        std::cout << "Done!\n";
        std::getchar();
    }
    catch (std::exception& e)
    {
        std::cout << "Exception: " << e.what();
        std::getchar();
    }
    return 0;
}

Код полностью рабочий, но хотелось бы разобраться, как он работает, без помощи не смогу разобраться :(

Если возможно, подскажите пожалуйста вот для примера эти строки:

tcp::resolver::query query(URL, "80");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

Что делают эти команды ?

Это что типа команды tracert ? Получает все промежуточные ip вплоть до конечного ?
Если да, то подскажите, как из вывести на консоль или записать в string эти данные ?
Если это вообще возможно ?


#1
13:58, 9 мая 2019

Резолвер получает ip сервера из его имени.
Посмотреть на ip можно так

ip::tcp::resolver::iterator iter = resolver.resolve( query);
ip::tcp::endpoint ep = *iter;
std::cout << ep.address().to_string() << std::endl;

#2
(Правка: 16:09) 16:00, 9 мая 2019

Смотри я тут с Api WG работаю, в моем репозитории поищи там много примеров работы с Boost asio.

https://github.com/IBets/HTTP/blob/master/main.cpp

Вообще почитай официльную доку и покодь немного на сырых сокетах и все встанет на места

#3
(Правка: 16:36) 16:35, 9 мая 2019

Walter Sullivan, Спасибо!
IBets, Спасибо! А что в данном случае значит "сырых" сокетах ?

#4
17:04, 9 мая 2019

Optimus1
Вот смотри на x2
https://www.youtube.com/watch?v=UKgvHcqF7GU&t=6120s

#5
20:35, 9 мая 2019

Нашел еще небольшое описание на этом же форуме:
https://gamedev.ru/code/articles/boost_asio_0

Там есть вот такое опиcание:

Для подключения к серверу используется метод connect объекта класса socket. В качестве параметра передается объект класса endpoint, указывающий куда подключаться:
tcp::socket the_client_socket(the_io_service);
the_client_socket.connect(the_client_endpoint);
В случае успешного соединения, можно приступать к передаче.

1)А что физически происходит в момент connect`а ? Со стороны клиента —> серверу через сокет посылается какой то запрос ?
2)А как узнать, что соединение успешное ? Сервер должен прислать какое то сообщение об этом ?
3)И если соединение успешное, то сколько такое соединение к примеру без дальнейших действий и запросов будет держатся ?
4)Что значит в данном случае вообще - "соединение" ?

#6
23:28, 9 мая 2019

Optimus1
Ну здесь надо матчасть изучать. Для начала скачай wireshark и просто посмотри как пересылаются пакеты данных. Сырые сокеты подключаются через IP адрес(условно считай каждому компу назначен уникальный идентификатор(PS:но на самом деле все сложнее, так как количество соединений больше чем количество IP-адресов)). Но так как сырыми IP - адресами пользоваться не особо удобно придумали протокол DNS. С помощью него устанавливается связь между доменным именем и IP-адресом. В операционной системе есть таблица корневых DNS серверов, через нее запрашивают у сервера соответствие между IP и доменным именем. Здесь очень много информации надо изучать, я не смогу тебе так просто в двух словах объяснить. Начни изучать модель OSI  и TCP/IP. Начни лучше со второй модели, так это не абстрактная выдумка 

#7
(Правка: 20:40) 10:42, 23 июля 2019

Здравствуйте,

read(socket, response, boost::asio::transfer_at_least(1), error)
Подскажите пожалуйста, что делает функция transfer_at_least(1) ?
Гуглил, но так и не понял ее назначение.

transfer_at_least(n) - показывает сколько минимально необходимо ждать байт для считывания, но тогда непонятно, чем она принципиально отличается от transfer_exactly(n).

#8
23:33, 26 июля 2019

В доке к этим функциям хорошие же примеры.

at_least сработает в диапазоне от n до макс. размера буфера, exactly когда в буфере будет точно число байт.
И если надо активно работать с http/https советую посмотреть в сторону boost.beast сделано поверх asio, еще и в вебсокеты умеет

#9
(Правка: 11:29) 11:28, 13 авг. 2019

Здравствуйте,

Подскажите пожалуйста, вот делаю async_resolve на boost asio, все работает, отправляется запрос на резолв, далее срабатывает handler. Но вопрос, как результат хендлера выаести из main ? К примеру, как вывести результат хендлера значение tcp::resolver::iterator endpoint_iterator в main ?

void handler_resolve(const boost::system::error_code& error, tcp::resolver::iterator endpoint_iterator)
 { 
if (!error) { std::cout << «Резолв успешен» << endl;

tcp::endpoint endo_pointo = *endpoint_iterator;

cout << endo_pointo.address().to_string() << endl; 
} 
else 
{ 
std::cout << «Ошибка: » << error.message() << endl;
}
}

int main() 
{ string URL_name="http://www.games.ru"

boost::asio::io_service io_services;

tcp::resolver resolvers(io_services); boost::system::error_code ec;

tcp::resolver::query query(URL_name, «80»); resolvers.async_resolve(query, handler_resolve); 
} 
io_services.run(); 
}

ПрограммированиеФорумСеть