2011-06-15 13 views
5

¿Cómo manejo el evento control-C o detengo mi servidor boost :: asio? Tengo un servidor combinado tcp & udp y me gustaría poder salir limpiamente cuando presiono ctrl-c. Tengo una excepción de primera oportunidad para el control no controlado-C. Aquí está mi códigocómo controlar el control-c en un servidor boost tcp/udp

void startTCP() 
{ 
    http::syncServer::server serv(2); 

// Set console control handler to allow server to be stopped. 
// console_ctrl_function = boost::bind(&http::syncServer::server::stop, &serv); 
//SetConsoleCtrlHandler(console_ctrl_handler, TRUE); 
// Run the server until stopped. 
serv.run(); 
} 


void startUDP() 
{ 
    boost::asio::io_service io_service; 
    http::syncServer::udp_server server(io_service); 
// console_ctrl_function = boost::bind(&http::syncServer::udp_server::stop, &server); 
// SetConsoleCtrlHandler(console_ctrl_handler, TRUE); 
io_service.run(); 
} 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
    boost::shared_ptr<boost::thread> tcpThread(new boost::thread(startTCP)); 
    boost::shared_ptr<boost::thread> udpThread (new boost::thread(startUDP)); 

    /*console_ctrl_function = boost::bind(&http::syncServer::udp_server::stop, &server); 
    SetConsoleCtrlHandler(console_ctrl_handler, FALSE);*/ 

    tcpThread->join(); 
    udpThread->join(); 
} 
catch (std::exception& e) 
{ 
    std::cerr << "exception: " << e.what() << "\n"; 
} 

return 0; 
} 
+1

posible duplicado de [manera estándar para realizar un apagado limpio con Boost.Asio ] (http://stackoverflow.com/questions/4639909/standard-way-to-perform-a-clean-shutdown-with-boost-asio) – CharlesB

Respuesta

4

La biblioteca estándar de C contiene <signal.h> (por ejemplo see here), con la que se puede registrar un manejador de señales para SIGINT (Ctrl-C). Eso debería funcionar, suponiendo que su plataforma admita señales.

Es posible que también desee registrar un controlador para SIGTERM para responder correctamente a kill (1) ed.

#include <signal.h> // or <csignal> in C++ 

void ctrlchandler(int) { /*...*/ WE_MUST_STOP = 1; } 
void killhandler(int) { /*...*/ WE_MUST_STOP = 2; } 

int WE_MUST_STOP = 0; 

int main() { 
    signal(SIGINT, ctrlchandler); 
    signal(SIGTERM, killhandler); 
    /* ... */ 

    // e.g. main loop like this: 
    while(pump_loop() && 0 == WE_MUST_STOP) { } 

} 

Como se sugiere por Sam Miller, supongamos que su bucle principal es un único subproceso de bucle boost.asio con un poco de m_io_service.run(). Entonces, en lugar de las banderas globales, podría (asumiendo que m_io_service es visible) post un manejador de tope al servicio io dentro de los manejadores de señal.

+0

Para ser una respuesta completa que debería sugerir cómo detener el bucle de evento 'io_service' dentro del controlador de señal. –

+0

OK, he agregado un comentario para ese fin, y agregué una condición de parada basada en indicador crudo al ejemplo principal. Dado que OP desea ejecutar los servicios de ASIO en hilos separados, supongo que tendrá su propio bucle principal dedicado en alguna parte. –

4

A partir del impulso de 1,47 puede utilizar signal_set de asio:

class Server { 
public: 
    Server(...) { 
    _signals.add(SIGINT); 
    _signals.add(SIGTERM); 
    _signals.async_wait(bind(&Server::handle_stop, this)); 

    } 
    void handle_stop() { 
    // do what you need to kill the Server - usually you just have to cancel all waits (incl deadline_timers), which will make the io_service exit gracefully 
    } 
private: 
    boost::asio::signal_set _signals; 
}; 

cuidado, versiones impulso de ejemplo La última versión de Ubuntu es 1.46, por lo que esta es la punta de lanza (primo 2012).

Cheers,

Michael

+0

Problemas con esta respuesta. R: El constructor signal_set necesita una referencia al io_service. B: la firma handle_stop es incorrecta. – ravenspoint

0

Puede utilizar signal_set de asio, como este

// stop on ctrlC signal 

boost::asio::signal_set signals(
    io_service, 
    SIGINT, 
    SIGTERM); 
signals.async_wait(
    boost::bind(
     &boost::asio::io_service::stop, 
     &io_service)); 

The docs are here

Cuestiones relacionadas