How do I handle the control-C event or stop my boost::asio server. I have a tcp & udp combined server and would like to be able to exit cleanly when I press ctrl-c. I get a first chance exception for unhandled control-C. Here is my code
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;
}
As of boost 1.47 you can use signal_set from 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;
};
Beware, boost versions of e.g. latest Ubuntu is 1.46 - so this is bleeding edge (primo 2012).
Cheers,
Michael
The C standard library contains <signal.h>
(e.g. see here), with which you can register a signal handler for SIGINT (Ctrl-C). That should do the trick, supposing your platform supports signals.
You might also want to register a handler for SIGTERM to respond gracefully to being 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) { }
}
As suggested by Sam Miller, suppose your main loop is a single-threaded boost.asio loop with some m_io_service.run()
. Then instead of the global flags you could (assuming m_io_service
is visible) post a stop handler to the io service from within the signal handlers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With