在Win32上停止进程最干净的方法?

时间:2008-09-17 10:15:04

标签: c user-interface winapi console ipc

在C ++中实现应用服务器及其客户端库时,我无法找到一种干净可靠的方法来停止Windows上服务器关闭时的客户端进程。

假设服务器及其客户端在同一用户下运行,则要求为:

  • 解决方案应该适用于以下情况:   
        
    • 客户可能每个都有控制台或gui。
    •   
    • 用户可能没有特权。
    •   
    • 客户端可能会或没有响应(无限循环,死锁)。
    •   
    • 客户可能是也可能不是服务器的子女(直接或间接)。
    •   
  • 除非被客户端缺陷阻止,否则客户应该有机会干净地退出(释放他们的资源,将一些数据同步到磁盘......)以及合理的时间。
  • 在关机过程中,所有客户端返回代码都应可用(如果可能)到服务器。
  • 服务器应等到所有客户都离开。

在此编辑中,以下大部分答案都提倡在服务器与其客户端之间使用共享内存(或其他IPC机制)来传达关闭命令和客户端状态。这些解决方案可行,但要求客户端成功初始化库。

我没有说的是,服务器也用于启动客户端,在某些情况下,其他程序/脚本根本不使用客户端库。一个不依赖于服务器和客户端之间优雅通信的解决方案会更好(如果可能的话)。

前一段时间,我偶然发现了一个C片段(在我认为的MSDN中)执行了以下操作:

  1. 在关闭过程中通过CreateRemoteThread启动一个线程。
  2. 让该线程直接调用ExitProcess。
  3. 不幸的是,现在我正在寻找它,我无法找到它,搜索结果似乎暗示这个技巧在Vista上不再起作用了。有专家的意见吗?

5 个答案:

答案 0 :(得分:2)

如果您使用线程,一个简单的解决方案是使用命名系统事件,线程在等待它发出信号的事件上休眠,控制应用程序可以在它希望客户端应用程序退出时发出信号。

对于UI应用程序,它(线程)可以将消息发布到主窗口,WM_ CLOSE或QUIT我忘记了,在控制台应用程序中它可以发出CTRL-C或者如果主控制台代码循环它可以检查线程设置的一些退出条件。

无论是哪种方式而不是找到告诉他们退出的客户端应用程序,使用操作系统来表示他们应该退出。如果使用WaitForSingleObject来休眠,则休眠线程几乎不会占用CPU占用空间。

答案 1 :(得分:1)

您希望在客户端和服务器之间使用某种IPC。如果所有客户都是孩子,我认为管道最简单;因为它们不是,我想服务器操作的共享内存段可用于注册客户端,发出shutdown命令,并收集客户端成功关闭后发布的返回代码。

在此共享内存区域中,客户端放置其进程ID,以便服务器可以使用TerminateProcess()强制终止任何无响应的客户端(模数据服务器权限)。

答案 2 :(得分:1)

如果您愿意使用IPC路由,请在客户端和服务器之间进行双向正常通信,让服务器请求客户端关闭。或者,如果没有,请让客户进行投票。或者作为最后的手段,应该指示客户端在向服务器发出请求时退出。您可以让库用户注册退出回调,但我知道的最好的方法是在客户端被告知关闭时在客户端库中调用“exit”。如果客户端陷入关闭代码,服务器需要能够通过忽略客户端的数据结构和连接来解决它。

答案 3 :(得分:1)

使用PostMessage或命名事件。

Re:PostMessage - GUI以外的应用程序以及GUI线程以外的线程都可以有消息循环,对于这样的东西非常有用。 (实际上COM在引擎盖下使用了消息循环。)我之前用ATL做过但是有点生疏了。

如果您希望对来自“错误”进程的恶意攻击保持健壮,请将客户端/服务器共享的私钥作为消息中的参数之一。

命名事件方法可能更简单;使用名称是客户端/服务器共享的秘密的CreateEvent,并让相应的应用程序在其主循环中检查事件的状态(例如,WaitForSingleObject的超时为0)以确定是否关闭。

答案 4 :(得分:0)

这是一个非常普遍的问题,并且存在一些不一致之处。

虽然它不是100%规则,但大多数控制台应用程序都会运行完成,而GUI应用程序会一直运行直到用户终止它们(并且服务一直运行直到通过SCM停止)。因此,请求GUI关闭更容易。你发送它们相当于Alt-F4。但是对于控制台程序,你必须发送它们相当于Ctrl-C并希望它们处理它。在这两种情况下,你只需等待。如果这个过程四处乱窜,你可以将它击落(TerminateProcess)并祈祷损坏是有限的。但是你的硬盘可以填满临时文件。

GUI应用程序一般没有退出代码 - 它们会去哪里?并且按定义强制终止的控制台进程不会退出,因此它没有退出代码。因此,在服务器关闭方案中,不要指望退出代码。

如果您连接了调试器,通常无法从其他应用程序关闭该进程。这将使调试器无法调试退出代码!