[英]Handling SIGINT or KeyboardInterrupt in Python 3 to exit gracefully using a “with socket” block
對於我要通過安全網絡通過tcp轉儲數據的項目,我嘗試編寫開發測試服務器以簡化測試過程。 我有服務器,它基本上只接收數據並將其打印到終端。
但是,我對當前的sigint處理實現不滿意。
我嘗試使用信號處理程序,並且嘗試/ except / finally阻塞各種配置都沒有用。
這是測試服務器的代碼
#!/usr/bin/env python3
import socket
import sys
host = ''
port = 5000
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
s.listen(1)
conn, addr = s.accept()
with conn:
print("Connected by", str(addr))
while True:
data = conn.recv(1024).decode()
if not data:
break
print(str(data))
except KeyboardInterrupt:
print("Quitting...")
finally:
sys.exit()
此版本退出時沒有堆棧跟蹤...那么,別無其他。
這是我嘗試過的事情和問題:
使用全局“偵聽”變量(在偵聽時)而不是while True,在這種情況下,sigint處理程序會將變量設置為false。 這意味着如果tcp套接字從不接受任何數據,它將根本不會以sigint終止,並且有必要使用sigquit或sigkill
在while True塊中或之前使用try catch塊。 再一次,在接受連接之前,這實際上並沒有任何幫助。
對整個主對象使用try catch。 這意味着我只能退出並偽造正常關機,而實際上卻不能。 另外,我認為這與使用with塊開頭的原則背道而馳。 (而且我不確定這種方法是否會關閉套接字,或者是否有必要)
這里有很多選擇,具體取決於您的關注點。 由於現在寫的......不,如果你的print
是不是一個長期的操作集,它不一定會完成,如果您鍵入Ctrl-C鍵。
您可以做的一件事是使用信號signal.pthread_sigmask
暫時阻止SIGINT
信號,例如,如果您不想中斷某個關鍵操作,則隨后對其進行屏蔽(這時SIGINT
將流照常傳遞到KeyboardInterrupt
)。 也可以通過上下文管理器來實現,如下所示:
#!/usr/bin/env python3
import signal
class SignalMasker:
""" Temporarily block signals. """
def __init__(self, sigs):
self.sigs = set(sigs)
def __enter__(self):
signal.pthread_sigmask(signal.SIG_BLOCK, self.sigs)
return self
def __exit__(self, *args):
signal.pthread_sigmask(signal.SIG_UNBLOCK, self.sigs)
return None
if __name__ == '__main__':
import time
interrupted = True
try:
with SignalMasker([signal.SIGINT]):
# Should not be able to interrupt this before 5 seconds expired
time.sleep(5)
interrupted = False
except KeyboardInterrupt:
print("\nGot keyboard interrupt")
assert not interrupted
如果您唯一要確保的是關閉文件描述符並避免堆棧跟蹤,那么現在所擁有的就可以了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.