web-dev-qa-db-ja.com

Python-KeyboardInterruptでメインスレッドを強制終了できません

単純なマルチスレッドポートスキャナーを作成しています。ホスト上のすべてのポートをスキャンし、開いているポートを返します。問題はスキャンの中断です。スキャンが完了するまでに時間がかかり、スキャンの途中でC-cを使用してプログラムを強制終了したい場合があります。問題は、スキャンが停止しないことです。メインスレッドはqueue.join()でロックされ、KeyboardInterruptを認識しません。これは、キューからのすべてのデータが処理され、メインスレッドのブロックが解除され、プログラムが正常に終了するまで続きます。私のスレッドはすべてデーモン化されているので、メインスレッドが死ぬと、彼と一緒に死ぬはずです。

Signal libを使用してみましたが、成功しませんでした。 threading.Threadクラスのオーバーライドと正常終了のためのメソッドの追加が機能しませんでした... queue.join()の実行中にメインスレッドがKeyboardInterruptを受信しません

import threading, sys, Queue, socket

queue = Queue.Queue()

def scan(Host):
    while True:
        port = queue.get()

        if port > 999 and port % 1000 == 0:
            print port
        try:
            #sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
            #sock.settimeout(2) #you need timeout or else it will try to connect forever! 
            #sock.connect((Host, port))
            #----OR----
            sock = socket.create_connection((Host, port), timeout = 2)

            sock.send('aaa')
            data = sock.recv(100)
            print "Port {} open, message: {}".format(port, data)
            sock.shutdown()
            sock.close()
            queue.task_done()
        except:
            queue.task_done()


def main(Host):
    #populate queue
    for i in range(1, 65536):
        queue.put(i)
    #spawn worker threads
    for port in range(100):
        t = threading.Thread(target = scan, args = (Host,))
        t.daemon = True
        t.start()

if __name__ == '__main__':
    Host = ""

    #does input exist?
    try:
        Host = sys.argv[1]
    except:
        print "No argument was recivied!"
        exit(1)

    #is input sane?
    try:
        Host = socket.gethostbyname(Host)
    except:
        print "Adress does not exist"
        exit(2)

    #execute main program and wait for scan to complete
    main(Host)
    print "Post main() call!"
    try:
        queue.join()
    except KeyboardInterrupt:
        print "C-C"
        exit(3)

編集:

時間モジュールを使用して解決策を見つけました。

#execute main program and wait for scan to complete
main(Host)

#a little trick. queue.join() makes main thread immune to keyboardinterrupt. So use queue.empty() with time.sleep()
#queue.empty() is "unreliable" so it may return True a bit earlier then intented.
#when queue is true, queue.join() is executed, to confirm that all data was processed.
#not a true solution, you can't interrupt main thread near the end of scan (when queue.empty() returns True)
try:
    while True:
        if queue.empty() == False:
            time.sleep(1)
        else:
            break
except KeyboardInterrupt:
    print "Alas poor port scanner..."
    exit(1)
queue.join()
12
RedSparrow

スレッドデーモンはすでに作成しましたが、デーモンスレッドが存在する間はメインスレッドを存続させる必要があります。その方法は次のとおりです。 Ctrl-CでPythonスクリプトを強制終了できません

4
solusipse

スレッドを作成するときは、実行中のスレッドのリストに追加し、ctrl-Cを処理するときは、リストの各スレッドにkillシグナルを送信します。そうすれば、あなたはそれがあなたのために行われていることに頼るのではなく、積極的に片付けをしているのです。

0
Steve Barnes