Python3.5 Asyncio TCP扫描仪

时间:2016-02-22 00:26:27

标签: python-3.x asynchronous tcp python-asyncio

我是Python3.5和Async的新手,除了在Python 2.7中少量使用Twisted之外。我将其构建为一个更大的应用程序,我需要一小部分而不是单片框架来执行TCP端口扫描。

import asyncio
from random import SystemRandom

def run(task, *, loop=None):
    if loop is None:
        loop = asyncio.get_event_loop()
    return loop.run_until_complete(asyncio.ensure_future(task, loop=loop))

async def scanner(ip, port, loop=None):
    fut = asyncio.open_connection(ip, port, loop=loop)
    try:
        reader, writer = await asyncio.wait_for(fut, timeout=0.5) # This is where it is blocking?
        print("{}:{} Connected".format(ip, port))
    except asyncio.TimeoutError:
        pass

def scan(ips, ports, randomize=False):
    if randomize:
        rdev = SystemRandom()
        ips = rdev.shuffle(ips)
        ports = rdev.shuffle(ports)
    for port in ports:
        for ips in ips:
            run(scanner(ip, port))

 ips = ["192.168.0.{}".format(i) for i in range(1, 255)]
 ports = [22, 80, 443, 8080]
 scan(ips, ports)

只要单个线程需要,这仍然需要。如何将其转换为异步TCP扫描程序?

1 个答案:

答案 0 :(得分:2)

run_until_complete正在阻塞,执行在那里停止并等待直到一次扫描结束,然后是下一次扫描......

您应安排所有(或部分)任务,并使用wait等待所有任务。

import asyncio
from random import SystemRandom

def run(tasks, *, loop=None):
    if loop is None:
        loop = asyncio.get_event_loop()
    # waiting for all tasks
    return loop.run_until_complete(asyncio.wait(tasks))

async def scanner(ip, port, loop=None):
    fut = asyncio.open_connection(ip, port, loop=loop)
    try:
        reader, writer = await asyncio.wait_for(fut, timeout=0.5) # This is where it is blocking?
        print("{}:{} Connected".format(ip, port))
    except asyncio.TimeoutError:
        pass
    # handle connection refused and bunch of others
    except Exception as exc:
        print('Error {}:{} {}'.format(ip, port, exc))

def scan(ips, ports, randomize=False):
    loop = asyncio.get_event_loop()
    if randomize:
        rdev = SystemRandom()
        ips = rdev.shuffle(ips)
        ports = rdev.shuffle(ports)

    # let's pass list of task, not only one
    run([scanner(ip, port) for port in ports for ip in ips])

ips = ["192.168.0.{}".format(i) for i in range(1, 255)]
ports = [22, 80, 443, 8080]
scan(ips, ports)

我还添加了except块来捕获其余的异常,包括拒绝最常见的连接。