簡體   English   中英

使用“ with socket”塊處理Python 3中的SIGINT或KeyboardInterrupt以正常退出

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM