2013-08-01 9 views
11

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

私は信号libを使ってみましたが、成功しませんでした。 queue.join実行中threading.Threadクラスをオーバーライドして動作しませんでした優雅な終了のためのメソッドを追加...メインスレッドだけで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) 

はEDIT:

私が発見しました時間のモジュールを使用してソリューション。

#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() 
+1

誰もが知っています?これは1トンのCPUを無駄にし、スレッドをスレッドを使用してしばらくの間Trueを回避します。 'thread.join'は、(CPU時間を無駄にする無限ループなしで)私がそれを殺すことができれば、完璧です。何か案は?しかし、私が実行しているテストでは、テスト目的と将来の参照のためにスレッドが無期限に(理論的には永遠に)続けるため、スレッドを終了する必要はありません(別の用語で 'pkill python'を実行するのは苦痛です。私は本当に知りたいです。ありがとう(とCtrl + Zをしないでください) – dylnmc

+0

これはWindows上で実行している場合、これは "正常"です。 PythonインタプリタはCTRL-Cをキャッチして内部フラグをセットし、制御がPythonの解釈に戻るのを待って 'KeyboardInterrupt'を発生させます。それは、内部フラグをチェックし戻すために 'EINTR'を返すシステムコールをブロックすることに頼っています。しかし、Windowsでのシステムのブロック操作は、そのようなことが起こったときに 'EINTR'エラーコードで返されないので、' KeyboardInterrupt'例外は、ブロック操作が完了するまで延期されます。 –

答えて

0

あなたはスレッドがリスト上の各スレッドにkillシグナルを送るスレッドを実行しているとCtrl-Cを扱うときのリストに追加作成します。あなたのために行われていることに頼るのではなく、積極的に清掃しています。

4

あなたはすでにあなたのスレッドのデーモンを作っていますが、デーモンスレッドがある一方で、それを行う方法があります生きているあなたのメインスレッドを維持する必要があります。while真ずにこれを行う方法があるかどうCannot kill Python script with Ctrl-C

+3

私のメインスレッドは生きています。 queue.join()は、キュー内のすべてのデータが処理されるまでスレッドをブロックします。その後、queue.join()はメインスレッドをデブロックし、プログラムは正常終了します。問題は、メインスレッドがqueue.join()に達すると、スレッドがKeyboardInterruptに対して「無力」になることです。メインスレッドを削除できない場合は、デーモンスレッドを強制終了できません。私は私の質問を明確にします... – RedSparrow

+0

多分これを試してください:http://stackoverflow.com/a/13570261/2031025 – solusipse

+0

あなたの提案をありがとうが、私は解決策を見つけた。 – RedSparrow

関連する問題