优雅地终止基于 Boost Asio 的 Windows 控制台应用程序
我正在开发基于 boost.asio 的 HTTP 服务器.它应该在外部停止.我们使用 asio 信号处理,它适用于 ctrl-c,但不处理 WM_CLOSE,因此没有直接的方法从外部优雅地关闭应用程序,例如通过 taskkill.强制终止进程不是一种选择.有没有已知的方法来解决这个问题?
I am working on a boost.asio based HTTP server. It is supposed to be stopped externally. We use asio signal handling, and it works well for ctrl-c, but does not handle WM_CLOSE, so there is no straightforward way to gracefully close the application externally, e.g. via taskkill. Terminating the process forcibly is not an option. Is there a known approach to this?
推荐答案
更新
只需使用您通常"使用的任何 IPC 方法
Just use any IPC method you would "normally" use
编写一个简单的过程控制实用程序,它使用例如
named_condition
通知你的 asio 进程关闭.
Write a simple process control utility that uses e.g.
named_condition
to signal your asio process to shutdown.
请注意,named_codition
有点等同于 Win32 命名事件,以防您认为对于这个固有平台特定的代码段更简单
Note that named_codition
is somewhat equivalent to a Win32 Named Event in case you think that simpler for this inherently platform specific piece of code
考虑制作一个 Windows 服务 (NTService),看起来像就像这就是你想要的
Consider making a Windows Service (NTService), as it looks like this is what you want
原答案,处理如何监听控制台关闭事件:
Original answer, dealing with how to listen for console close events:
这确实与使用 Boost Asio 无关.当然,在 POSIX 平台上,您可以使用 boost::asio::signal_set
来处理 SIG_INT 和 SIG_TERM 信号.
This is really not related to using Boost Asio. Of course, on POSIX platforms you could use boost::asio::signal_set
to handle the SIG_INT and SIG_TERM signals.
但是,您使用的是 Windows,并且没有可移植的方法来检测控制台关闭事件.
However, you're on windows, and there is no portable way to detect console close event.
您应该编写一个控制台处理程序例程来检测 CTRL_CLOSE_EVENT(和 CTRL_C_EVENT,如果需要),并使用 SetConsoleCtrlHandler 将处理程序例程添加到您的进程中.
You should write a console handler routine that detects CTRL_CLOSE_EVENT (and CTRL_C_EVENT, if desired), and use SetConsoleCtrlHandler to add the handler routine to your process.
#include <windows.h>
#include <stdio.h>
BOOL CtrlHandler( DWORD fdwCtrlType )
{
switch( fdwCtrlType )
{
// Handle the CTRL-C signal.
case CTRL_C_EVENT:
printf( "Ctrl-C event
" );
Beep( 750, 300 );
return( TRUE );
// CTRL-CLOSE: confirm that the user wants to exit.
case CTRL_CLOSE_EVENT:
Beep( 600, 200 );
printf( "Ctrl-Close event
" );
return( TRUE );
// Pass other signals to the next handler.
case CTRL_BREAK_EVENT:
Beep( 900, 200 );
printf( "Ctrl-Break event
" );
return FALSE;
case CTRL_LOGOFF_EVENT:
Beep( 1000, 200 );
printf( "Ctrl-Logoff event
" );
return FALSE;
case CTRL_SHUTDOWN_EVENT:
Beep( 750, 500 );
printf( "Ctrl-Shutdown event
" );
return FALSE;
default:
return FALSE;
}
}
int main( void )
{
if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) )
{
printf( "
The Control Handler is installed.
" );
printf( "
-- Now try pressing Ctrl+C or Ctrl+Break, or" );
printf( "
try logging off or closing the console...
" );
printf( "
(...waiting in a loop for events...)
" );
while( 1 ){ }
}
else
{
printf( "
ERROR: Could not set control handler");
return 1;
}
return 0;
}
为了与 Boost Asio 协调,您可以让处理程序停止(全局)io_service 对象,并可能为运行操作设置一些标志.最后,您可能必须取消任何正在进行的异步操作(例如 deadline_timer
s).
To coordinate with Boost Asio, you could have the handler stop the (global) io_service object and perhaps set some flag for running actions. Finally, you may have to cancel any async operations in flight (e.g. deadline_timer
s).
一旦你这样做了,它应该很干净.
Once you did that, it should be pretty clean.
相关文章