多线程端口扫描仪

时间:2013-05-27 20:20:11

标签: python multithreading sockets python-2.7

是的,是的,我知道我可以使用nmap,但我想自己尝试一下。

我正在尝试编写一个线程脚本来查找目标IP地址上的开放端口。这就是我现在所拥有的:

import socket, Queue
from threading import Thread


print "Target to scan: "
targetIP = raw_input("> ")
print "Number of threads: "
threads = int(raw_input("> "))


q = Queue.Queue()

# Fill queue with port numbers
for port in range(1, 1025):
    q.put(port)


def scan(targetIP, port):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(4)
        result = s.connect_ex((targetIP, port))
        if result == 0:
            print 'Port {0} is open'.format(port)
        s.close
        q.task_done()



while q.full:
    for i in range(threads):
        port = q.get()
        t = Thread(target=scan, args =(targetIP, port))
        t.daemon = True
        t.start()

但是我有一些问题:

1)当我按原样运行时,它将遍历端口队列,但只是挂起,即使队列清空,也不会从while循环中断。

2)如果我向scan添加打印行以查看发生了什么,基本上在开头添加“扫描端口X”行,最后添加print result行,stdout充满了队列中所有端口的“扫描端口”行,然后打印结果行。意思是,看起来目前脚本不是在等result获取值,而是继续迭代,就像它有了一样。

我在这里做错了什么?

5 个答案:

答案 0 :(得分:4)

您的实际问题已由少数人解答,因此这是使用multiprocessing.Pool代替threading的替代解决方案:

import socket

from multiprocessing import Pool

def scan(arg):
    target_ip, port = arg

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(2)

    try:
        sock.connect((target_ip, port))
        sock.close()

        return port, True
    except (socket.timeout, socket.error):
        return port, False

if __name__ == '__main__':
    target_ip = raw_input('Target IP: ')
    num_procs = int(raw_input('Number of processes: '))

    ports = range(1, 1025)
    pool = Pool(processes=num_procs)

    for port, status in pool.imap_unordered(scan, [(target_ip, port) for port in ports]):
        print port, 'is', 'open' if status else 'closed'

答案 1 :(得分:2)

这里有几个问题,第一个是:

while q.full:

据推测,你打算调用这个函数:

while q.full():

但是你有一个无限的队列(你创建它没有maxsize),所以它永远不会满;所以如果你做了那个改变,它根本不会调用scan()。

假设您以其他方式解决此问题(例如,使用q.empty()),如果range(threads)不能均匀划分队列中的项目,会发生什么?例如,假设您使用3个线程并将端口号1,2,3和4放入q。您将在第一次旅行中通过外部q.get()呼叫while三次(获得1,2和3),然后在第二次旅行中再次呼叫三次 - 但它只有一次其中包含更多价值,4,因此在此之后调用q.get()会等待某人执行q.put(),您将陷入困境。

换句话说,你需要改写逻辑。

修改:与s.close vs s.close()相同的问题。其他人解决了整个线程方面的问题。使用multiprocessing的@Blender版本要简单得多,因为multiprocessing会为你处理这个问题。

答案 2 :(得分:1)

您的代码存在一些问题。首先,while循环一直持续到q.full,这是一个函数,是假的。但实际上没有必要在主线程中循环。

我会将sentinel值添加到队列的末尾,每个工作线程一个。当工作线程获得哨兵时,它退出其处理循环。这样您就不必守护线程了。

所以你的代码应该是:

  • 将端口放入队列
  • 将哨兵列入队列
  • 启动所需数量的线程,让它们从队列中获取端口并处理它们,将结果放入另一个队列中
  • 等待线程终止,在worker
  • 上调用t.join()
  • 使用结果

答案 3 :(得分:0)

嗯,你必须知道只需遍历线程数范围内的数字并执行线程,就不会保留所需线程的数量。它只循环4次,创建4个线程,再次循环并进入另一个相同的循环并创建另外4个而不确定那些4完成了他们的任务,因此当您将打印件放入扫描功能时,您将获得大量消息。

您必须等待孩子们在身体部分结束时完成。

我想:

threading.wait()

做到了。

答案 4 :(得分:-1)

试试这个:

import socket
import threading
from queue import Queue

print_lock = threading.Lock()

target = 'pythonprogramming.net'

def portscan(port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        con = s.connect((target,port))
        with print_lock:
            print('port',port,'is open!')
        con.close()
    except:
        pass

def threader():
    while True:
        worker = q.get()
        portscan(worker)
        q.task_done()

q = Queue()

for x in range(30):
    t = threading.Thread(target=threader)
    t.daemon = True
    t.start()


for worker in range(1,10000):
    q.put(worker)

q.join()