1

アプリケーションサーバーとそのクライアント側ライブラリをC++で実装しているときに、Windowsのサーバーシャ​​ットダウン時にクライアントプロセスを停止するためのクリーンで信頼性の高い方法を見つけるのに苦労しています。

サーバーとそのクライアントが同じユーザーの下で実行されていると仮定すると、要件は次のとおりです。

  • このソリューションは、次の場合に機能するはずです。
    • クライアントはそれぞれ、コンソールまたはGUIのいずれかを備えている場合があります。
    • ユーザーには特権がない可能性があります。
    • クライアントは応答しなくなるか、応答しなくなる可能性があります(無限ループ、デッドロック)。
    • クライアントはサーバーの子である場合とそうでない場合があります(直接または間接)。
  • クライアント側の欠陥によって防止されない限り、クライアントはクリーンに終了する機会(リソースを解放し、一部のデータをディスクに同期する...)と、そうするための妥当な時間を許可されるものとします。
  • すべてのクライアントリターンコードは、シャットダウン手順中にサーバーで利用できるようにする必要があります(可能な場合)。
  • サーバーは、すべてのクライアントがなくなるまで待機する必要があります。

この編集の時点で、以下の回答の大部分は、サーバーとそのクライアント間で共有メモリ(または別のIPCメカニズム)を使用してシャットダウン命令とクライアントステータスを伝達することを推奨しています。これらのソリューションは機能しますが、クライアントがライブラリを正常に初期化する必要があります。

私が言わなかったことは、サーバーはクライアントを起動するためにも使用され、場合によってはクライアントライブラリをまったく使用しない他のプログラム/スクリプトも使用されるということです。サーバーとクライアント間の適切な通信に依存しないソリューションの方が優れています(可能な場合)。

しばらく前に、次のことを行うCスニペット(MSDNで私が信じている)に出くわしました。

  1. シャットダウンするプロセスでCreateRemoteThreadを介してスレッドを開始します。
  2. そのスレッドにExitProcessを直接呼び出させました。

残念ながら、今探しているのですが、見つけることができず、検索結果は、このトリックがVistaでは機能しなくなったことを示唆しているようです。これに関する専門家の意見はありますか?

4

5 に答える 5

2

スレッドを使用する場合の簡単な解決策は、名前付きシステム イベントを使用することです。スレッドは、イベントが通知されるのを待ってスリープし、制御アプリケーションは、クライアント アプリケーションを終了させたいときにイベントを通知できます。

UIアプリケーションの場合、それ(スレッド)はメインウィンドウ、WM_CLOSEまたはQUITにメッセージを投稿できますコンソールアプリケーションではCTRL-Cを発行できるか、メインコンソールコードがループする場合は終了条件を確認できますスレッドによって設定されます。

いずれにせよ、クライアント アプリケーションに終了するように指示するのではなく、OS を使用して終了するように通知します。スリープ スレッドは、WaitForSingleObject を使用してスリープする場合、実質的に CPU フットプリントを使用しません。

于 2008-09-17T12:48:42.100 に答える
1

クライアントとサーバーの間にある種の IPC が必要です。すべてのクライアントが子供だったら、パイプが最も簡単だったと思います。そうではないので、サーバーが操作する共有メモリセグメントを使用して、クライアントを登録し、シャットダウンコマンドを発行し、正常にシャットダウンしたクライアントによってポストされたリターンコードを収集できると思います。

この共有メモリ領域では、クライアントはプロセス ID を配置するため、サーバーは TerminateProcess() を使用して、応答しないクライアント (モジュロ サーバー特権) を強制的に終了できます。

于 2008-09-17T10:27:18.740 に答える
1

IPC ルートを使用する場合は、クライアントとサーバー間の通常の通信を双方向にして、サーバーがクライアントにシャットダウンを要求できるようにします。または、それに失敗した場合は、クライアントにポーリングさせます。または、最後の手段として、クライアントがサーバーにリクエストを送信したときにクライアントを終了するように指示する必要があります。ライブラリ ユーザーに終了コールバックを登録させることもできますが、私が知っている最善の方法は、クライアントがシャットダウンするように指示されたときに、クライアント ライブラリで単に "exit" を呼び出すことです。クライアントがシャットダウン コードで動かなくなった場合、サーバーはそのクライアントのデータ構造と接続を無視することで問題を回避できる必要があります。

于 2008-09-17T12:51:06.523 に答える
1

PostMessage または名前付きイベントを使用します。

Re: PostMessage -- GUI 以外のアプリケーション、および GUI スレッド以外のスレッドはメッセージ ループを持つことができ、このようなものには非常に便利です。(実際、COM は内部でメッセージ ループを使用します。)以前に ATL でそれを行ったことがありますが、それには少し慣れていません。

「悪い」プロセスからの悪意のある攻撃に対して堅牢にしたい場合は、クライアント/サーバーが共有する秘密鍵をメッセージのパラメータの 1 つとして含めます。

名前付きイベントのアプローチは、おそらくより単純です。クライアント/サーバーによって共有される秘密の名前で CreateEvent を使用し、適切なアプリにメイン ループ内のイベントのステータス (たとえば、タイムアウトが 0 の WaitForSingleObject) をチェックさせて、シャットダウンするかどうかを決定します。

于 2008-12-24T00:13:02.790 に答える
0

これは非常に一般的な質問であり、いくつかの矛盾があります。

100% のルールではありませんが、ほとんどのコンソール アプリケーションは完了するまで実行されますが、GUI アプリケーションはユーザーが終了するまで実行されます (そしてサービスは SCM によって停止されるまで実行されます)。したがって、GUI を閉じるように要求する方が簡単です。Alt-F4に相当するものを送ります。しかし、コンソール プログラムの場合は、Ctrl-C に相当するものを送信して、それが処理されることを期待する必要があります。どちらの場合も、待つだけです。プロセスが残っている場合は、プロセスを停止 (TerminateProcess) し、被害が限定されることを祈ります。ただし、HDD が一時ファイルでいっぱいになることがあります。

一般に、GUI アプリケーションには終了コードがありません。終了コードはどこに行くのでしょうか? また、定義によって強制終了されるコンソール プロセスは終了しないため、終了コードはありません。そのため、サーバーのシャットダウン シナリオでは、終了コードを期待しないでください。

デバッガーが接続されている場合、通常、別のアプリケーションからプロセスをシャットダウンすることはできません。これにより、デバッガーが終了コードをデバッグできなくなります。

于 2008-09-17T10:28:20.160 に答える