私は現在、シェルで実行されている専用サーバーのラッパーに取り組んでいます。ラッパーはサブプロセスを介してサーバープロセスを生成し、その出力を監視して反応します。
専用サーバーには、正常にシャットダウンするコマンドを明示的に指定する必要があります。したがって、CTRL-Cはサーバープロセスに到達してはなりません。
KeyboardInterrupt例外をキャプチャするか、PythonでSIGINTハンドラーを上書きしても、サーバープロセスは引き続きCTRL-Cを受け取り、すぐに停止します。
だから私の質問は:サブプロセスがCTRL-C/Control-C/SIGINTを受け取らないようにする方法は?
#python IRC-Channel(Freenode)の誰かが、subprocess.Popen(...)のpreexec_fnパラメーターを指摘してくれました。
preexec_fnが呼び出し可能オブジェクトに設定されている場合、このオブジェクトは、子が実行される直前に子プロセスで呼び出されます。 (Unixのみ)
したがって、次のコードは問題を解決します(UNIXのみ)。
import subprocess
import signal
def preexec_function():
# Ignore the SIGINT signal by setting the handler to the standard
# signal handler SIG_IGN.
signal.signal(signal.SIGINT, signal.SIG_IGN)
my_process = subprocess.Popen(
["my_executable"],
preexec_fn = preexec_function
)
注:シグナルは実際にはサブプロセスに到達することを妨げられていません。代わりに、上記のpreexec_fnは、シグナルのデフォルトハンドラーを上書きして、シグナルが無視されるようにします。したがって、このソリューションmayは、サブプロセスが[〜#〜] sigint [〜#〜]ハンドラーを再度上書きすると機能しません。
別の注意:このソリューションは、あらゆる種類のサブプロセスで機能します。つまり、Pythonで記述されたサブプロセスにも制限されません。たとえば、ラッパーを作成している専用サーバーは、実際にはJavaで作成されています。
トリックを実行する他のいくつかの回答を組み合わせると、メインアプリに送信されたシグナルはサブプロセスに転送されません。
import os
from subprocess import Popen
def preexec(): # Don't forward signals.
os.setpgrp()
Popen('whatever', preexec_fn = preexec)
あなたはそれをウィンドウズとUNIXで動作させるためにこのようなことをすることができます:
import subprocess
import sys
def pre_exec():
# To ignore CTRL+C signal in the new process
signal.signal(signal.SIGINT, signal.SIG_IGN)
if sys.platform.startswith('win'):
#https://msdn.Microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
#CREATE_NEW_PROCESS_GROUP=0x00000200 -> If this flag is specified, CTRL+C signals will be disabled
my_sub_process=subprocess.Popen(["executable"], creationflags=0x00000200)
else:
my_sub_process=subprocess.Popen(["executable"], preexec_fn = pre_exec)