如何在Python中实现键盘中断

如何在Python中实现键盘中断,python,python-multithreading,keyboardinterrupt,port-scanning,Python,Python Multithreading,Keyboardinterrupt,Port Scanning,我正在用python编写一个端口扫描程序,一切正常,但我想实现crtl+c中断函数来终止程序。它会停止主程序,但仍有线程在运行。如何使用ctrl+c键完全终止程序 class StatusChecker(threading.Thread): """ The thread that will check HTTP statuses. """ #: The queue of urls url_queue = None #: The queue ou

我正在用python编写一个端口扫描程序,一切正常,但我想实现crtl+c中断函数来终止程序。它会停止主程序,但仍有线程在运行。如何使用ctrl+c键完全终止程序

class StatusChecker(threading.Thread):
    """
    The thread that will check HTTP statuses.
    """

    #: The queue of urls
    url_queue = None

    #: The queue our results will go into
    result_queue = None

    #: An event that tells the thread to stop
    stopper = None

    def __init__(self, url_queue, result_queue, stopper):
        super().__init__()
        self.url_queue = url_queue
        self.result_queue = result_queue
        self.stopper = stopper

    def run(self):
        print_lock = threading.Lock()
        while not self.stopper.is_set():
            try:
                # this will throw queue.Empty immediately if there's
                # no tasks left
                to_check = self.url_queue.get_nowait()
            except queue.Empty:
                break # empty queue, we're done!
            else:
                with print_lock:
                    print(to_check,' ')
                self.url_queue.task_done() # the the queue we're done


class SignalHandler:
    """
    The object that will handle signals and stop the worker threads.
    """

    #: The stop event that's shared by this handler and threads.
    stopper = None

    #: The pool of worker threads
    workers = None

    def __init__(self, stopper, workers):
        self.stopper = stopper
        self.workers = workers

    def __call__(self, signum, frame):
        """
        This will be called by the python signal module

        https://docs.python.org/3/library/signal.html#signal.signal
        """
        self.stopper.set()

        for worker in self.workers:
            worker.join()

        sys.exit(0)


if __name__ == '__main__':
    # all the variables we'll need
    num_workers = 2
    stopper = threading.Event()
    result_queue = queue.Queue()
    url_queue = queue.Queue()

    # populate our work queue
    for i in range(65535):
        url_queue.put(i)

    # we need to keep track of the workers but not start them yet
    workers = [StatusChecker(url_queue, result_queue, stopper) for i in range(num_workers)]

    # create our signal handler and connect it
    #handler = SignalHandler(stopper, workers)
    #signal.signal(signal.SIGINT, handler)

    # start the threads!
    for i, worker in enumerate(workers):
        print('Starting worker {}'.format(i))
        worker.daemon = True
        worker.start()

    # wait for the queue to empty
    try:
        while threading.active_count() > 0:
            time.sleep(0.1)
    except:
        sys.exit(0)
    while not result_queue.empty():
        url, status = result_queue.get_nowait()
        print('{} - {}'.format(url, status))

线程与主进程共享相同的内存空间。因此,从技术上讲,在主进程上执行ctrl-c应该释放线程内存。如果线程处于写入的中间,那么它可能是不安全的,但否则它应该是OK的。否则,您可以使用python的库并创建一个信号处理程序来捕获SIGINT