使用多线程、多进程和协程扫描ip和可用的端口

此脚本意在学习多线程threading、多进程multiprocessing、协程以及subprocess的使用。使用subprocess调用系统的ping命令检测给定的ip地址是否能ping通,使用socket扫描给定的ip地址有哪些可用的端口。
利用subprocess调用系统的ping命令,函数实现如下:

def ping(host):
    """Returns True if host responds to a ping request"""
    ping_str = "-n 1" if platform.system().lower() == "windows" else "-c 1"
    return subprocess.call("ping " + ping_str + " " + host, shell=True) == 0

使用装饰器编写了一个计时器,以便比较多线程、多进程和协程的性能

def used_time(name):
    name = 'Using the {0} to scan ip '.format(name)
    def wrapper(func):
        @functools.wraps(func)
        def _wrapper(*args, **kwargs):
            global available_ip
            start_time = timer()
            func(*args, **kwargs)
            the_time_used = timer() - start_time
            print_available_ip()
            available_ip = []
            print name + "takes {:.3f} seconds".format(the_time_used)
        return _wrapper
    return wrapper

举个例子,使用多线程检测ip是否ping得通:

@used_time('threads')
def threads_scan_ip():
    """I use 64 threads,you can change it base on your situation"""
    q = Queue.Queue()
    for prefix in ip_prefix:
        map(q.put, xrange(length_of_ip_suffix))
        threads = [threading.Thread(target=ping_worker, args=(prefix, q, None)) for i in xrange(64)]
        map(lambda t: t.start(), threads)
        map(lambda t: t.join(), threads)

值得注意的是,在统计程序运行时间的时候,在Windows中最好使用time.clock()函数,而在其他平台上最好使用time.time()。Python中time.clock()和time.time()的区别这个网页中有详细的说明,可以学习。

if platform.system().lower() == "windows":
    timer = time.clock
else:
    timer = time.time

学习到什么
在multiprocessing模块中,多个进程之间共享变量可以使用 multiprocessing.Value,multiprocessing.Array 或者 使用multiprocessing.Manager,并且需要将你想要共享的变量作为参数传递到进程中才能成功。详见python标准库(建议多看python官方文档,好处多多)
在Windows下使用multiprocessing,有可能会出现如下错误:

RuntimeError:Attempt to start a new process before the current process
            has finished its bootstrapping phase.This probably means that you are on Windows and you have
            forgotten to use the proper idiom in the main module:if __name__ == '__main__':
                    freeze_support()...The "freeze_support()" line can be omitted if the program
            is not going to be frozen to produce a Windows executable.

解决方法是在使用multiprocessing模块里面的类和函数之前,添加multiprocessing.freeze_support()语句,并确保在if __name__ == '__main__'下执行代码。

如果你想看看源代码,可以点击这里

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器