Boost asio :: accept blocking behavior [duplicate]

Упрощенный oneliner: 1

function hasClassName(classname,id) {
 return  String ( ( document.getElementById(id)||{} ) .className )
         .split(/\s/)
         .indexOf(classname) >= 0;
}

1 indexOf для массивов не поддерживается IE (конечно). Для этого есть множество патчей для обезьян.

25
задан Tanner Sansbury 25 June 2012 в 19:52
поделиться

4 ответа

Короче говоря, есть два варианта:

  • Измените код, который будет асинхронным (acceptor::async_accept() и async_read), запустите в цикле событий через io_service::run() и отмените через io_service::stop().
  • Блокировать блокировку вызовов для прерывания с помощью механики нижнего уровня, например сигналов.

Я бы порекомендовал первый вариант, так как он скорее всего будет переносной и более простой в обслуживании. Важное понятие для понимания состоит в том, что io_service::run() блокируется только до тех пор, пока не выполняется работа. Когда вызывается io_service::stop() , он попытается как можно скорее вернуть все потоки, заблокированные на io_service::run(); он не будет прерывать синхронные операции, такие как acceptor::accept() и socket::receive(), даже если синхронные операции вызывают в цикле событий. Важно отметить, что io_service::stop() является неблокирующим вызовом, поэтому синхронизация с потоками, которые были заблокированы на io_service::run(), должна использовать другой механизм, такой как thread::join() .

Вот пример, который будет работать в течение 10 секунд и будет прослушивать порт 8080:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <iostream>

void StartAccept( boost::asio::ip::tcp::acceptor& );

void ServerThreadFunc( boost::asio::io_service& io_service )
{
  using boost::asio::ip::tcp;
  tcp::acceptor acceptor( io_service, tcp::endpoint( tcp::v4(), 8080 ) );

  // Add a job to start accepting connections.
  StartAccept( acceptor );

  // Process event loop.
  io_service.run();

  std::cout << "Server thread exiting." << std::endl;
}

void HandleAccept( const boost::system::error_code& error,
                   boost::shared_ptr< boost::asio::ip::tcp::socket > socket,
                   boost::asio::ip::tcp::acceptor& acceptor )
{
  // If there was an error, then do not add any more jobs to the service.
  if ( error )
  {
    std::cout << "Error accepting connection: " << error.message() 
              << std::endl;
    return;
  }

  // Otherwise, the socket is good to use.
  std::cout << "Doing things with socket..." << std::endl;

  // Perform async operations on the socket.

  // Done using the socket, so start accepting another connection.  This
  // will add a job to the service, preventing io_service::run() from
  // returning.
  std::cout << "Done using socket, ready for another connection." 
            << std::endl;
  StartAccept( acceptor );
};

void StartAccept( boost::asio::ip::tcp::acceptor& acceptor )
{
  using boost::asio::ip::tcp;
  boost::shared_ptr< tcp::socket > socket(
                                new tcp::socket( acceptor.get_io_service() ) );

  // Add an accept call to the service.  This will prevent io_service::run()
  // from returning.
  std::cout << "Waiting on connection" << std::endl;
  acceptor.async_accept( *socket,
    boost::bind( HandleAccept,
      boost::asio::placeholders::error,
      socket,
      boost::ref( acceptor ) ) );
}

int main()
{
  using boost::asio::ip::tcp;

  // Create io service.
  boost::asio::io_service io_service;

  // Create server thread that will start accepting connections.
  boost::thread server_thread( ServerThreadFunc, boost::ref( io_service ) );

  // Sleep for 10 seconds, then shutdown the server.
  std::cout << "Stopping service in 10 seconds..." << std::endl;
  boost::this_thread::sleep( boost::posix_time::seconds( 10 ) );
  std::cout << "Stopping service now!" << std::endl;

  // Stopping the io_service is a non-blocking call.  The threads that are
  // blocked on io_service::run() will try to return as soon as possible, but
  // they may still be in the middle of a handler.  Thus, perform a join on 
  // the server thread to guarantee a block occurs.
  io_service.stop();

  std::cout << "Waiting on server thread..." << std::endl;
  server_thread.join();
  std::cout << "Done waiting on server thread." << std::endl;

  return 0;
}

Во время работы я открыл два подключения. Вот результат:

Stopping service in 10 seconds...
Waiting on connection
Doing things with socket...
Done using socket, ready for another connection.
Waiting on connection
Doing things with socket...
Done using socket, ready for another connection.
Waiting on connection
Stopping service now!
Waiting on server thread...
Server thread exiting.
Done waiting on server thread.
27
ответ дан Tanner Sansbury 23 August 2018 в 21:36
поделиться

Когда вы получаете сообщение о том, что пришло время выхода, вы можете вызвать acceptor.cancel(), который отменит ожидающий прием (с кодом ошибки operation_canceled). В некоторых системах вы также можете close() принять акцептор, чтобы быть в безопасности.

3
ответ дан Dave S 23 August 2018 в 21:36
поделиться

Просто вызовите shutdown с помощью встроенного дескриптора и опции SHUT_RD, чтобы отменить существующую операцию приема (accept).

0
ответ дан JohnYu 23 August 2018 в 21:36
поделиться

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

3
ответ дан Martin James 23 August 2018 в 21:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: