我有这个服务器草案,在新客户端连接后分叉新子节点。然后取决于客户端的命令子服务器在函数处理程序(连接)中做一些工作。
与此同时,我想停止父服务器,在此之前让父母等待所有工作的孩子。
问题是我应该在哪里为Ctrl+C
键盘中断选项设置此信号功能。
signal.signal(signal.SIGINT,signal_handler)
children_list = []
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.bind((HOST, PORT))
conn.listen(5)
print("Listening on TCP port %s" % PORT)
def reaper(pids):
while children_list:
pid,stat = os.waitpid(0, os.WNOHANG)
if not pid:
break
pids.remove(pid)
def handler(connection):
cmd = connection.recv(socksize)
def signal_handler(signal, frame):
print 'You pressed Ctrl+C!'
sys.exit(0)
def accept():
while 1:
global connection
connection, address = conn.accept()
print "welcome new client!"
reaper(children_list)
pid = os.fork()
if pid:#parent
children_list.append(pid)
connection.close()
else:#child
handler(connection)
accept()
答案 0 :(得分:0)
问题是我应该在何处为Ctrl + C键盘中断选项设置此信号功能。 signal.signal(signal.SIGINT,signal_handler)
您想要的任何地方,只要在您定义signal_handler
之后和拨打accept
之前。
我不确定信号处理程序实际上是你想要的。在大多数平台上,您实际正在做的事情会立即退出,就像您要求的那样,导致孩子们被重新定位到init
或launchd
或类似物品。但你想要真正等待所有的孩子。因此,您无法拨打exit
。
在POSIX中,您不得在信号处理程序内拨打waitpid
。 Python信号处理程序不是真正的信号处理程序,因此可能不相关 - 但我不认为这个事实在任何地方都可以保证。如果您想承担风险,可以尝试在signal_handler
之前等待所有孩子,然后再致电exit
,看看它是否适用于您的平台。
但是,标准的POSIX方法是让信号处理程序设置一些全局标志并返回。然后,主程序将从accept
或其他正在等待的EINTR
错误的其他阻塞调用中唤醒,此时它可以检查标志 - 如果为true,则等待孩子的时间并退出;否则,再次回到循环和accept
。
但无论如何所有这一切都不是必要的。默认的SIGINT处理程序应该只引发KeyboardInterrupt
,这意味着 - 如果你没有安装自定义信号处理程序 - 你真正需要做的就是捕获该异常。换句话说,只需用最后一行替换:
try:
accept()
except KeyboardInterrupt: # or maybe BaseException
# wait for children, blocking instead of WNOHANG of course
sys.exit(0)