最干净的方法来停止Win32上的进程?
在用C ++实现应用服务器及其客户端库时,我很难找到一种干净可靠的方法来在Windows服务器关闭时停止客户端进程。
假设服务器及其客户端在同一用户下运行,则要求是:
- 客户端可以是(也可以不是)服务器的子级(直接或者间接)。
- 除非受到客户端缺陷的阻止,否则应允许客户端有机会干净地退出(释放其资源,将一些数据同步到磁盘...),并有一些合理的时间这样做。
- 在关闭过程中,应将所有客户端返回代码提供给服务器(如果可能)。
- 服务器应等待所有客户端消失。
在进行此编辑时,以下大多数答案都主张在服务器及其客户端之间使用共享内存(或者其他IPC机制)来传达关闭命令和客户端状态。这些解决方案可以使用,但是需要客户端成功初始化库。
我没有说的是,服务器还用于启动客户端,在某些情况下还用于根本不使用客户端库的其他程序/脚本。一个不依赖服务器和客户端之间正常通信的解决方案会更好(如果可能)。
前一段时间,我偶然发现了一个C片段(在我相信的MSDN中),该片段执行以下操作:
- 在关闭过程中通过CreateRemoteThread启动线程。
- 让该线程直接调用ExitProcess。
不幸的是,现在我正在寻找它,我找不到它,并且搜索结果似乎暗示此技巧在Vista上不再起作用。有什么专家意见吗?
解决方案
回答
我们需要客户端和服务器之间的某种IPC。如果所有客户都是孩子,我认为管道将是最简单的。因为它们不是,所以我猜可以使用服务器操作的共享内存段来注册客户端,发出shutdown命令以及收集成功关闭客户端发布的返回代码。
在此共享内存区域中,客户端放置了其进程ID,以便服务器可以使用TerminateProcess()强制终止任何无响应的客户端(模服务器特权)。
回答
这是一个非常普遍的问题,并且存在一些不一致之处。
尽管这不是100%的规则,但是大多数控制台应用程序都可以运行完成,而GUI应用程序可以运行直到用户终止它们为止(服务一直运行到通过SCM停止为止)。因此,请求关闭GUI更容易。我们发送给他们相当于Alt-F4. 但是对于控制台程序,我们必须向他们发送等效于Ctrl-C的控件,并希望他们能够处理它。在这两种情况下,我们只需等待。如果该过程仍然存在,则可以将其击落(TerminateProcess),并祈祷其损坏是有限的。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。但是HDD可以填充临时文件。
GUI应用程序通常没有退出代码,它们会去哪里?并且被定义强行终止的控制台进程不会退出,因此它没有退出代码。因此,在服务器关闭的情况下,不要期望退出代码。
如果我们已连接调试器,则通常无法从另一个应用程序中关闭该进程。这将使调试器无法调试退出代码!
回答
如果使用线程,一个简单的解决方案是使用命名的系统事件,线程在事件上休眠以等待被信号通知,控制应用程序可以在希望客户端应用程序退出时向事件发送信号。
对于UI应用程序,它(线程)可以将消息发布到主窗口中,WM_ CLOSE或者QUIT我忘记了,在控制台应用程序中它可以发出CTRL-C,或者如果主控制台代码循环了,它可以检查某些退出条件由线程设置。
无论哪种方式,都不要使用指示操作系统退出的客户端应用程序,而是使用OS发出信号指示退出应用程序。如果睡眠线程使用WaitForSingleObject进行睡眠,则实际上将不占用任何CPU资源。
回答
如果我们愿意使用IPC路由,请使客户端和服务器之间进行正常的双向通信,以使服务器要求客户端关闭。否则,请客户进行投票。或者作为最后的手段,当向服务器发出请求时,应指示客户端退出。我们可以让库用户注册退出回调,但是据我所知,最好的方法是在告诉客户端关闭时,在客户端库中简单地调用" exit"。如果客户端陷入关闭代码中,则服务器需要能够通过忽略该客户端的数据结构和连接来解决该问题。
回答
使用PostMessage或者命名事件。
回复:PostMessage-GUI以外的应用程序以及GUI线程以外的线程可能具有消息循环,这对于诸如此类的事情非常有用。 (实际上,COM在幕后使用了消息循环。)我之前使用ATL做到过,但是对此有些生锈。
如果要对来自"不良"进程的恶意攻击保持鲁棒性,请包括客户端/服务器共享的私钥作为消息中的参数之一。
命名事件方法可能更简单;使用名称为客户端/服务器共享的机密名称的CreateEvent,并让相应的应用在其主循环内检查事件的状态(例如,超时为0的WaitForSingleObject),以确定是否关闭。