写了一个 forking 多进程socket 的 server 原型
运行系统是FB。 却发现 ctrl + c 无法关闭这个正在监听的程序。
import socket,traceback,os,sys import signal,time def reap(): while 1: try: result = os.waitpid(-1,os.WNOHANG) if not result[0]: break except: break print "reap process %d" % result[0] def sigint_handler(signum,frame): print 'eeexxeexx' #s.close() print 'close' sys.exit() signal.signal(signal.SIGINT,sigint_handler) host = 'localhost' port = 9009 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) s.bind((host,port)) s.listen(1) print "parent at %d" % os.getpid() while 1: try: clientsock,clientaddr = s.accept() except: #print sys.exc_info()[0] traceback.print_exc() time.sleep(2) print os.getpid() continue #s.close() #sys.exit() reap() pid = os.fork() if pid: clientsock.close() continue else: s.close() try: print "child is %d" % 2 while 1: data = clientsock.recv(4096) if not len(data): break clientsock.sendall(data) time.sleep(10) print "%s" % data except: raise sys.exit(0)
看代码
首先。 我自定义捕获ctrl + c 信号
def sigint_handler(signum,frame): print 'eeexxeexx' #s.close() print 'close' sys.exit() signal.signal(signal.SIGINT,sigint_handler)
在捕获信号里面 使用了 sys.exit()退出 程序。
再看下监听部分:
while 1: try: clientsock,clientaddr = s.accept() except: #print sys.exc_info()[0] traceback.print_exc() #time.sleep(2) print os.getpid() continue #s.close() #sys.exit()
不断在监听,是否有客户端连接,如果产生异常就 continue 继续回到上头去监听。
问题:为啥就ctrl + c 就退出不了呢。加了调试参数(就是带注释的那些)研究了半天。终于明白了
ctrl +c 以后抛出了 KeyboardInterrupt 异常,而我在捕获信号函数里面,又使用了 sys.exit()方法,这个方法会抛出 SystemExit
这个看手册才知道: This is implemented by raising the SystemExit exception
异常而覆盖了前面的 KeyboardInterrupt。 就这样代码是以 SystemExit异常而跑到了 except: 异常处理区。 而异常处理区里我使用了 continue 让程序回到监听状态。就这样导致了 sys.exit() 无效了等于。 可以做个小实验证明这个答案是否正确。 看上面代码,我在异常处理区加入了 time.sleep(2) 让程序在异常处理区卡住运行两秒。
然后再运行这个程序。结果是。我连续按两下 ctrl + c ,就可以正常退出了 程序。 这个很好理解了。 因为当我第一次按下 ctrl + c 的时候。程序跑到了 异常处理区而且 time.sleep(2) 两秒。 就在这会我继续 来多一次 ctrl + c 等于又多发出一个异常。但这会的程序是运行在异常处理区,而异常处理区我没有再处理这里发生的异常了。所以这会代码就运行到这里
def sigint_handler(signum,frame): print 'eeexxeexx' #s.close() print 'close' sys.exit()
sys.exit() 发出了退出的异常。没人接收这个异常的话,就直接退出了程序。
解决办法就是。不要 捕获 KeyboardInterrupt 和 SystemExit 。
本文探讨了一个Python Socket Server中遇到的问题,即使用Ctrl+C无法正常关闭多进程监听程序。通过深入分析异常处理流程,特别是KeyboardInterrupt与SystemExit之间的相互作用,找到了合理的解决方案。
1372

被折叠的 条评论
为什么被折叠?



