我正在制作一个简单的多线程端口扫描器。它会扫描主机上的所有端口并返回打开的端口。问题在于如何中断扫描。扫描需要很长时间才能完成,有时我希望在扫描中途使用C-c杀死程序。但是问题在于扫描不会停止。主线程被锁定在queue.join()上,忽略KeyboardInterrupt,直到队列中所有数据被处理完毕,因此解除了主线程的阻塞并优雅地退出程序。我的所有线程都是守护线程,因此当主线程死亡时,它们也应该随之死亡。
我尝试使用signal lib,但没有成功。覆盖threading.Thread类并添加用于优雅终止的方法也没有起作用...当执行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)
编辑:
我通过使用time模块找到了解决方案。
#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()
thread.join
更完美,只是我能歇菜(而不需要浪费CPU时间的无限循环)。有什么想法吗? 我将要运行的测试并不需要我杀掉线程,因为线程会无限期地继续下去(从理论上讲,它会永远继续下去),但出于测试目的和将来的参考(因为每次都在另一个终端窗口执行pkill python
很繁琐),我真的想知道。 谢谢(别说ctrl + z) - dylnmcKeyboardInterrupt
。 它依赖于阻塞系统调用返回EINTR
,以便返回并检查该内部标志。 但是,在Windows上,当发生这种情况时,阻止系统操作不会返回EINTR
错误代码,因此KeyboardInterrupt
异常将延迟直到阻止操作完成。 - André Caron