父服务器分支需要及时退出



我有一个服务器草稿,它在新的客户端连接后派生新的子级。然后依赖于客户端的命令,子服务器在函数处理程序(连接)中执行一些工作。

同时,我想停止父服务器,在此之前让父服务器等待所有工作的子服务器。

问题是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()

问题是,对于Ctrl+C键盘中断选项,我应该把这个信号函数放在哪里。signal.signal(signal.SIGINT,signal_handler)

任何您想要的位置,只要是在定义signal_handler之后和调用accept之前。

我不确定信号处理程序是否真的是您想要的。在大多数平台上,你实际做的事情会立即退出,就像你要求它退出一样,导致孩子们对initlaunchd或类似的东西做出反应。但你真的想等所有的孩子。所以,您不能调用exit

在POSIX中,不允许在信号处理程序中调用waitpid。Python信号处理程序不是真正的信号处理程序,所以这个可能不相关——但我认为这一事实在任何地方都不能保证。如果你想冒险,你可以试着在呼叫exit之前,在signal_handler中等待所有的孩子,看看它在你的平台上是否有效。

然而,标准的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)

最新更新