Проблема со ссылками (я думаю) при использовании boost :: asio - PullRequest
1 голос
/ 12 мая 2011

Я строю HTTP-клиент на основе примера на HTTP-сервере, приведенном по адресу boost website . Теперь разница между этим кодом и моим заключается в том, что в примере используется конструктор сервера для запуска асинхронных операций. Это имеет смысл, поскольку сервер должен постоянно слушать. В моем клиенте, с другой стороны, я хочу сначала создать объект, а затем использовать функцию send(), которая начинается с подключения к конечной точке, а затем отправляет запрос и, наконец, прослушивает ответ. Это тоже имеет смысл, не так ли?

Когда я создаю свой объект (клиент), я делаю это так же, как в примере с сервером (winmain.cpp). Это выглядит так:

client c("www.boost.org);
c.start(); // starts the io_service in a thread
c.send(msg_);

Соответствующие части кода следующие:

void enabler::send(common::geomessage& msg_)
{
    new_connection_.reset(new connection(io_service_,
        connection_manager_,
        message_manager_, msg_
    ));

    boost::asio::ip::tcp::resolver resolver(io_service_);
    boost::asio::ip::tcp::resolver::query query(host_address, "http");

    resolver.async_resolve(query, boost::bind(
        &enabler::handle_resolve,
        boost::ref(*this),
        boost::asio::placeholders::error,
        boost::asio::placeholders::iterator
    ));
}

void enabler::run()
{
    io_service_.run();
}

Проблема в том, что программа застревает где-то здесь. Последнее, что печатает, это «Разрешающий хост», после чего программа заканчивается. Я не знаю почему, потому что io_service должен блокироваться, пока все асинхронные операции не вернутся к своим обратным вызовам. Однако, если я изменяю порядок вызова функций, это работает. Если я позвоню run() сразу после вызова async_resolve(), а также опущу вызов start() в моей основной программе, это работает!

В этом сценарии io_service блокируется как следует, и я вижу, что я получаю ответ от сервера.

Это связано с тем, что я называю run() из того же класса, где я называю async_resolve(). Может ли это быть правдой? Я полагаю, мне нужно дать ссылку из основной программы, когда я звоню run(), это так?

Я изо всех сил пытался заставить io_service::work работать, но программа просто зависает, и да, возникают проблемы, аналогичные описанным выше. Так что это не очень помогает.

Итак, что я могу сделать, чтобы понять это правильно? Как я уже говорил ранее, я хочу иметь возможность создавать клиентский объект и постоянно запускать io_service в отдельном потоке внутри клиентского класса. Во-вторых, иметь функцию send(), которая отправляет запросы на сервер.

Ответы [ 2 ]

2 голосов
/ 12 мая 2011

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

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

0 голосов
/ 13 мая 2011

Если вы не ожидаете, что у вас всегда будет какая-то работа, чтобы сохранить занятость io_service, вы должны создать объект io_service::work в некоторой области, в которую можно выйти, не возвращая io_service::run() в первую очередь.Если вы запускаете io_service в отдельном потоке, я бы предположил, что у вас не будет проблем с этим.

Трудно понять, что вы пытаетесь делать с этими фрагментамикод.Я полагаю, что вы хотели бы сделать что-то вроде этого:

struct client
{
   io_service io_service_;
   io_service::work* w_;
   pthread_t main_thread_;
   client(): w_(new io_service::work(io_service)) { ... }
   void start() { pthread_create(&main_thread_, 0, main_thread, this); }
   static long main_thread(void* arg) { ((client*)arg)->io_service_.run(); }
   // release the io_service and allow run() to return
   void stop() { delete w_; w_ = 0; pthread_join(main_thread_); }
};
...