2013-08-01 23 views
11

Sto facendo un semplice port scanner multi-thread. Esegue la scansione di tutte le porte sull'host e restituisce le porte aperte. Il problema sta interrompendo la scansione. Ci vuole molto tempo prima che una scansione sia completata e, a volte, desidero uccidere il programma con C-c mentre sono nel mezzo della scansione. Il problema è che la scansione non si fermerà. Il thread principale è bloccato su queue.join() e ignaro di KeyboardInterrupt, finché non vengono elaborati tutti i dati dalla coda, in modo da sbloccare il thread principale e uscire dal programma con garbo. Tutti i miei thread sono demonizzati, quindi quando il thread principale muore dovrebbero morire con lui.Python - Impossibile interrompere il thread principale con KeyboardInterrupt

Ho provato a utilizzare signal lib, non riuscito. Override classe threading.Thread e metodo per la terminazione aggraziato non ha funzionato l'aggiunta di ... thread principale solo non riceverà KeyboardInterrupt durante l'esecuzione queue.join()

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:

ho trovato un soluzione utilizzando il modulo del tempo.

#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

Qualcuno sa se c'è un modo per fare questo senza un po 'di vero ? Questo spreca un sacco di CPU e sto usando Thread dal threading per evitare un po 'True. 'thread.join' è perfetto se solo potessi ucciderlo (senza un ciclo infinito di tempo per la CPU). Qualche idea? Il test che eseguirò non richiede che lo uccida perché il thread continua indefinitamente (teoricamente continuerà per sempre), tuttavia, per scopi di test e riferimenti futuri (dal momento che è un dolore fare 'pkill python' in un altro termine finestra ogni volta), mi piacerebbe davvero sapere. Grazie (e non dire ctrl + z) – dylnmc

+0

Se stai eseguendo questo su Windows, questo è "normale". L'interprete Python cattura CTRL-C e imposta un flag interno, quindi attende che il controllo ritorni all'interpretazione di Python in modo che possa generare 'KeyboardInterrupt'. Si affida al blocco delle chiamate di sistema per restituire 'EINTR' per tornare indietro e controllare quella bandiera interna. Tuttavia, il blocco delle operazioni di sistema su Windows non viene restituito con un codice di errore 'EINTR' quando accade una cosa del genere, quindi l'eccezione' KeyboardInterrupt' viene ritardata fino al completamento dell'operazione di blocco. –

risposta

0

Quando si creano i fili li aggiungono a un elenco di thread in esecuzione e quando si tratta di ctrl-C inviano un segnale di interruzione per ogni thread sulla lista. In questo modo stai attivamente ripulendo piuttosto che fare affidamento su di esso per te.

4

hai fatto il tuo thread demoni già, ma è necessario tenere in vita mentre thread demoni sono lì il tuo thread principale, c'è come fare: Cannot kill Python script with Ctrl-C

+3

Il mio thread principale è vivo. queue.join() blocca il thread fino a quando tutti i dati nella coda vengono elaborati, quindi queue.join() disattiva il thread principale e il programma termina normalmente. Il problema è che quando il thread principale raggiunge queue.join() rende il thread "immune" a KeyboardInterrupt. Se non riesco a eliminare il thread principale, non posso uccidere i thread daemon. Chiarirò la mia domanda ... – RedSparrow

+0

Forse prova questo: http://stackoverflow.com/a/13570261/2031025 – solusipse

+0

Grazie per i tuoi suggerimenti, ma ho trovato una soluzione. – RedSparrow

Problemi correlati