LINUX.ORG.RU

Boost.Asio и несколько async_write/async_read за раз

 , ,


0

1

И снова здравствуйте! )

Получилось ПОЧТИ что хотел - за одно подключение-рукопожатие при пиковом (за время полного цикла от подключения до записи в сокет) поступлении команд через mqtt удается отправить херову гору rest-запросов, затем происходит отключение и ожидание следующей порции.

Но вот что нормально НЕ работает, так это CPush::handle_read_status, получаю туда после первого нормального response какой то мусор с периодической ошибкой от буста Operation canceled

Описание

class CPush
{
private:
    std::deque<std::string> dq;

    std::mutex mtx;
    std::condition_variable cv;

    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> * psocket;

    std::string request;
    boost::asio::streambuf response;

    bool verify_certificate(bool preverified, boost::asio::ssl::verify_context & ctx);
    void handle_connect(const boost::system::error_code & error);
    void handle_handshake(const boost::system::error_code & error);
    void handle_write(const boost::system::error_code & error);
    void handle_read_status(const boost::system::error_code & error);
    void handle_read_header(const boost::system::error_code & error);
    void handle_read_content(const boost::system::error_code & error);

    void Write(void);
    int Get(std::string & http);

public:

    CPush(void) { std::cout << "PUSH client initialized" << std::endl; }

    int Put(const std::string & tokens, const std::string & cmd);

    bool Wait(void);
    void Handler(void);
};

Частично реализация

void CPush::handle_handshake(const boost::system::error_code & error)
{
    if (error)
        std::cerr << "Handshake failed: " << error.message() << std::endl;
    else
        Write();
}

void CPush::handle_write(const boost::system::error_code & error)
{
    if (error)
      std::cerr << "Write failed: " << error.message() << std::endl;
    else
    {
        std::cout << "Sending request OK!" << std::endl;

        boost::asio::async_read_until(*psocket,
                                response, "\r\n",
                                boost::bind(&CPush::handle_read_status,
                                            this,
                                            boost::asio::placeholders::error));

        Write();
    }
}

void CPush::handle_read_status(const boost::system::error_code & error)
{
    if (error)
        std::cout << "Error read status: " << error.message() << std::endl;
    else
    {
std::cout << "!!!!!!!!!!!!!!!!!!!\n" << &response << "\n!!!!!!!!!!!!!!!!!!!\n" << std::flush;
        // Check that response is OK.
        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;
        }

        if (status_code != 200)
        {
            std::cout << "Response returned with status code ";
            std::cout << status_code << "\n";
//          return;
        }

/*      // Read the response headers, which are terminated by a blank line.
        boost::asio::async_read_until(*psocket,
                                        response, "\r\n\r\n",
                                        boost::bind(&CPush::handle_read_header,
                                                    this,
                                                    boost::asio::placeholders::error));
*/    }
}

int CPush::Get(std::string & http)
{
    std::lock_guard<std::mutex> lock(mtx);

    int rt = dq.size();
    if (rt > 0)
    {
        http = dq.front();
        dq.pop_front();
    }

    return rt;
}

void CPush::Write(void)
{
    if (Get(request) > 0)
        boost::asio::async_write(*psocket,
                                boost::asio::buffer(request),
                                boost::bind(&CPush::handle_write,
                                            this,
                                            boost::asio::placeholders::error));
}

int CPush::Put(const std::string & tokens, const std::string & cmd)
{
    std::string json("{\"registration_ids\":[" + tokens + "],"
                    "\"notification\":null,"
....................
                    "\"priority\":\"high\","
                    "\"time_to_live\":15}");

    mtx.lock();

    dq.push_back("POST " + std::string(GOOGLE_API) + " HTTP/1.1\r\n"
                "Host: " + GOOGLE_HOST + "\r\n" // << ":" << port
                "Content-Type: application/json; charset=utf-8\r\n"
                "Content-Length: " + std::to_string(json.size()) + "\r\n"
                "Authorization: key=" + push_key + "\r\n\r\n" + json);
    int rt = dq.size();

    mtx.unlock();
    cv.notify_one();

    return rt;
}

bool CPush::Wait(void)
{
    std::unique_lock<std::mutex> ul(mtx);
    do {
        if (!abRun) return false;
    } while (!cv.wait_for(ul, std::chrono::seconds(1), [this]{ return dq.size() > 0; }));

    return true;
}

void CPush::Handler(void)
{
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::resolver::query query(GOOGLE_HOST, GOOGLE_PORT);
    boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

    boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
    context.set_default_verify_paths();

    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(io_service, context);
    socket.set_verify_mode(boost::asio::ssl::context::verify_none);
    socket.set_verify_callback(boost::bind(&CPush::verify_certificate, this, _1, _2));

    psocket = &socket;

    boost::asio::async_connect(psocket->lowest_layer(),
                                iterator,
                                boost::bind(&CPush::handle_connect,
                                            this,
                                            boost::asio::placeholders::error));

    io_service.run();
std::cout << "00000000000000000000000000000000000" << std::endl;
}

запускаю все это дело из основного потока

std::thread ([](void){ while (pPush->Wait()) pPush->Handler(); }).detach();

и добавляю команды из другого потока по событию

pPush->Put(tokens_, cmd_);
★★★

Последнее исправление: wolverin (всего исправлений: 2)

получается я не могу одновременно послать 2 команды на запись и на чтение т.к. они не выполняются последовательно, но если переместить Write() в конец обработчика handle_read_status, то мусор все равно никуда не девается…

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

тоже похоже не подходит ))

вопщим добавил пока что

boost::asio::streambuf.commit(boost::asio::placeholders::bytes_transferred)

потом может дойдет как правильно читать или подскажет кто

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

кстати - прочитать асинхронно MQTT данные, сходить в MySQL в рамках бесконечного локального коннекта - БЫСТРЕЕ, чем REST запросы пишутся-читаются, так что те кто говорит что http клиент на плюсах не узкое место - бздят!

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Мне вот реально интересно, насколько бы меньше граблей собрал бы на своем пути начинающий C++ программист, пока еще не очень понимающий чем const std::string request в качестве параметра отличается от const std::string & request, если бы он последовал бы советам и выбрал бы не голый Boost.Asio, а Boost.Beast или cpp-netlib, или какую-то из готовых C++ных оберток над libcurl (да хоть бы и сам голый libcurl)?

PS. Мнение ыкспертов о том, что libcurl добавляет несколько сотен мегабайт к потреблению памяти оставим на совести ыкспертов.

eao197 ★★★★★
()
Ответ на: комментарий от wolverin

ответ на ваш же вопрос - это неявное преобразование типов

Шта, прассыте?

хотя накой это мне

Чтобы не терять производительность на ненужных копированиях на ровном месте, если вы понимаете о чем я. Хотя вряд ли.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Шта, прассыте?

ничо ничо, даже гюры иногда что то да не знают

https://habr.com/ru/companies/otus/articles/669114/

на ненужных копированиях на ровном месте

лучше иногда иметь копию, чем получить обращение к освобожденной памяти в многопоточном приложении.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

даже гюры

«Гюры» – это кто?

https://habr.com/ru/companies/otus/articles/669114/

На заборе тоже иногда всякое пишут. На какой именно фрагмент этой простыни нужно посмотреть?

лучше иногда иметь копию, чем получить обращение к освобожденной памяти в многопоточном приложении.

Э… У вас функция вида:

void do_request(const std::string req, const std::string cmd) {...}

уже вызывается на контексте какой-то нити. Как-то вот так:

void thread_body() {
  for(;;) {
    ...
    auto req = ...;
    auto cmd = ...;
    do_request(req, cmd);
  }
}

Так что в месте вызова вы имеете локальные объекты на стеке конкретной рабочей нити.

Осторожность следует применять при передаче информации между тредами. Но т.к., вы делаете вызов условного do_request уже на конкретном треде, то все предохранения нужно было сделать до того как.

Так в чем выгода от передачи req/cmd в do_request в виде константных объектов?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

На заборе тоже иногда всякое пишут.

да тут тоже всякое пишут, например, кому кем работать и чем в жизни заниматься и как работодателю не повезло и прочу куету.

«Гюры» – это кто?

те что не «ыксперты»

У вас функция вида

у меня функция вида

void do_request(const std::string & req, const std::string & cmd) {...}

хотя опять же это в моей простыне читать надо было, а так проще до чего то несущественного до.баться

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

да тут тоже всякое пишут, например, кому кем работать и чем в жизни заниматься и как работодателю не повезло и прочу куету.

Еще раз: вы сказали, что «это неявное преобразование типов».

Какая разница для «неявного преобразования типов» между «const std::string req» и «const std::string & req» мне непонятно. Отсюда и вопрос. На который вы кидаете ссылку на простыню спорного текста, а на просьбу указать на конкретное место в этой простыне мягко говоря посылаете вдоль.

Я правильно понял ваше поведение?

те что не «ыксперты»

Отлично. Что это за слово-то хоть? Какое-то производное от «гуру»?

у меня функция вида

void do_request(const std::string & req, const std::string & cmd) {…}

хотя опять же это в моей простыне читать надо было, а так проще до чего то несущественного до.баться

Хотите точных цитат? Их есть у меня:

void CPush::Send(const std::string tokens, const std::string cmd)
{

Пожалуйста: tokens и cmd передаются как константные значения. Что в точности соответствует сказанному мной: «начинающий C++ программист, пока еще не очень понимающий чем const std::string request в качестве параметра отличается от const std::string & request»

Так что вы на это все скажите?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Так что вы на это все скажите?

Скажу что вам врач нужен, уж очень ЧСВ зрение портит, но не уверен - окулист или психиатр.

int Put(const std::string & tokens, const std::string & cmd);
wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Скажу что вам врач нужен, уж очень ЧСВ зрение портит, но не уверен - окулист или психиатр

Давайте по порядку.

Вопрос №1: это - boost::asio::async_write вызывает Segmentation fault - ваша тема?

Вопрос №2: я задал здесь несколько вопросов. Вы собираетесь на них ответить?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

))) бхааа, я грит задал в одной теме вопросы по другой теме, в которой я искал ошибку обращения к освобожденной памяти, еще поищите темы мои и сюда их приплетите.

давай досвидания (с)

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

еще поищите темы мои

Да запросто. Тут же все ходы записаны.

А вот то, что вы на простые конкретные вопросы не можете ответить – это показательно.

На этот форум вы зачем хотите? Чтобы помощь от людей получить, не так ли? А зачем с вами общаться, если вы на конкретные встречные вопросы тупо морозитесь?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Чтоб от таких как вы послушать кем мне работать и чем заниматься ))

Увольте меня от общения лично с вами, я лучше подольше поразбираюсь чем херню вашу читать.

А и да дизлайк забыли скока раз поставить.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)
Ответ на: комментарий от wolverin

я лучше подольше поразбираюсь

Количество созданных вами тем наводит на обратное впечатление.

чем херню вашу читать.

Примеры «херни» можно увидеть? Или даже так: с вас цитата из моих слов, в которой вы видите «херню» (с явным указанием на эту самую «херню»), а я вам поясню почему это было написано. Идет?

А и да дизлайк забыли скока раз поставить.

Не заслужили пока. Перлы вроде «так что те кто говорит что http клиент на плюсах не узкое место - бздят!» случаются не часто.

eao197 ★★★★★
()
Ответ на: комментарий от wolverin

Т.е. бросить в собеседника «пишете херню» легко, а подтвердить это – уже обосратушки?

Как скучно.

Впрочем, чего ожидать от персонажа, который сливается даже указать на конкретный фрагмент статьи, ссылку на которую он же сам привел.

eao197 ★★★★★
()
Ответ на: комментарий от wolverin

О… А вы не только в C++ сильны, но еще и в боксе по переписке.

Батенька, может пока мы еще в рамках LOR-а, вы найдете в себе силы ответить на заданные здесь вопросы. Там же совсем немного. Две штуки.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Так а чего тянуть, приедите услышите, в с++ я конечно же не силен, это что то из очередной вашей херни выдумано.

Хотя куда вы поедите, так языком только в интернете махать можете.

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Хотя куда вы поедите, так языком только в интернете махать можете.

Если вы не заметили, мы все (все!) здесь исключительно этим и занимаемся. Включая вас.

Так я все-таки хотел бы услышать ответы на заданные здесь вопросы. Уверяю, это займет не сильно больше времени, чем очередная попытка меня как-то зацепить или обещание еще что-нибудь сломать.

И если вы не понимаете, почему это важно, то еще раз:

На этот форум вы зачем хотите? Чтобы помощь от людей получить, не так ли? А зачем с вами общаться, если вы на конкретные встречные вопросы тупо морозитесь?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Хотите на здоровье, общение с вами у меня вызывает отвращение, но если хотите тут понты покидать кто тут обосратушки, то для вас я всегда готов доказать лично кто тут обосрется, пишите если надумаете встречу.

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Хотите на здоровье, общение с вами у меня вызывает отвращение

Это поэтому вы меня сегодня два раза скастили в разные темы (раз, два)? Типа, скакали за мной два дня, чтобы сказать насколько я вам безразличен. OK.jpg

но если хотите тут понты покидать кто тут обосратушки

Еще раз повторю: здесь все ходы записаны. Вы позвали меня в тему, затем наговорили вещей, которые я не очень понял, на встречные вопросы отвечать отказались.

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

Где вы тут какие-то понты увидели – хз. Но спрашивать конкретные цитаты, очевидно, бесполезно.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ну не позвал конечно, вы сначала как обычно пришли насрали дизы, потом чтоб у вас ещё была такая возможность я ещё написал пост с упоминанием вас, потому что обычно вы молча срете в моих темах

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Так ответьте же хотя бы на вопрос о том, какая разница между const std::string req и const std::string & req с точки зрения неявных преобразований типов.

Заметьте, это исключительно технический вопрос заданный в техническом форуме в корректной форме, без переходов на личности. Причем исключительно после того, как вы такую заявку сделали по собственной инициативе, за язык вас никто не тянул.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ок макну вас последний раз в вашу же херню, как с ссылкой на левую тему - мой пост в 14:01 с упоминанием вас, ваш диз в 13:57, кто тут за кем бегает очевидно

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Да все сделал спасибо, разобрался сам

В таком случаи рекомендую ознакомится с этой штукой. Это совсем не обязательно, но скорее всего твою жизнь упростит. Стеб в этом посте тоже искать не обязательно.

dvetutnev
()
Ответ на: комментарий от wolverin

Ок макну вас последний раз в вашу же херню, как с ссылкой на левую тему - мой пост в 14:01 с упоминанием вас, ваш диз в 13:57, кто тут за кем бегает очевидно

Ну как так-то: REST через Boost.Asio (комментарий) от 11.08.23 05:01:42 MSK

Вы зачем-то упомянули меня в разговоре с совсем другим человеком.

Затем: Boost.Asio и несколько async_write/async_read за раз (комментарий) это уже 11.08.23 12:01:59 MSK

Вы еще раз зачем-то меня упомянули, вероятно обиделись на мою реакцию на ваше сообщение. При этом я вам ничего не писал, вам нужно было зачем-то меня позвать специально.

Повторяю в N-ый раз: здесь же ходы записаны, зачем нужно позориться?

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от eao197

А так вы просто ходите срать по моим темам, а не потому что за мной!? Ну тогда там выше вариант с окулистом считаю отпал, определенно нужен не этот врач.

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

А так вы просто ходите срать по моим темам

Вы не поверите, но когда здесь задают технические вопросы, то люди заходят в эти темы посмотреть, что за вопрос и как можно помочь (или узнать что-то новое).

У некоторых форумчан формируется специфическая репутация, из-за которой в их темы заходить желания становится все меньше и меньше. Вы сегодня в этом направлении сделали как никогда много. Чтож, ваше право.

Однако, вы постоянно уводите разговор в область персоналий. Тогда как есть технический вопрос, ответ на который мне (а может и не только мне) было бы интересно услышать: Boost.Asio и несколько async_write/async_read за раз (комментарий)

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ну вот я очень бы хотел чтоб лично вы не заходили в мои темы, даже просил вас, но видать словесный и прочие поносы вы не контролируете физиологически

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Ну вот я очень бы хотел чтоб лично вы не заходили в мои темы, даже просил вас

Ничего не сможете поделать, это публичный формум. Но есть хинт: LOR позволяет добавлять пользователей в игнор лист.

но видать словесный и прочие поносы вы не контролируете физиологически

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

eao197 ★★★★★
()

Boost.Asio и несколько async_write/async_read за раз

Организуй очередь у себя в программе, а Asio корми по одной операции чтения/записи за раз.

после первого нормального response какой то мусор

Передал в асинхронную операцию адрес буфера, но изменил содержимое буфера до окончания асинхронной операции. Следи за временем жизни буферов внимательнее.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Да там проблема с чтением буфера у меня, бууст хитро не только из сокета читает, но и в буфер складывает, сделал немного по другому через bytes_transferred, пока так нормально, надо доки мне больше почитать про этот streambuf, коммиты, консьюмы и тд

wolverin ★★★
() автор топика