利用python實現IP掃描

    需求:寫一個腳本,判斷192.168.11.0/24網絡裏,當前在線ip有哪些?python

    知識點:shell

    1 使用subprocess模塊,來調用系統命令,執行ping 192.168.11.xxx 命令網絡

    2 調用系統命令執行ping命令的時候,會有返回值(ping的結果),須要用到stdout=fnull, stderr=fnull方法,屏蔽系統執行命令的返回值app

     

    常規版本(代碼)異步

    import os
    import time
    import subprocess
    def ping_call():
        start_time = time.time()
        fnull = open(os.devnull, 'w')
        for i in range(1, 256):
            ipaddr = 'ping 192.168.11.' + str(i)
            result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull)
            current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime())
            if result:
                print('時間:{} ip地址:{} ping fall'.format(current_time, ipaddr))
            else:
                print('時間:{} ip地址:{} ping ok'.format(current_time, ipaddr))
        print('程序耗時{:.2f}'.format(time.time() - start_time))
        fnull.close()
    ping_call()

    執行效果:async

    blob.png


    上面的執行速度很是慢,怎麼能讓程序執行速度快起來?ide

    python提供了進程,線程,協程。分別用這三個對上面代碼改進,提升執行效率,測試一波效率測試


    進程池異步執行 -- 開啓20個進程spa

    import os
    import time
    import subprocess
    from multiprocessing import Pool
    def ping_call(num):
        fnull = open(os.devnull, 'w')
        ipaddr = 'ping 192.168.11.' + str(num)
        result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull)
        current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime())
        if result:
            print('時間:{} ip地址:{} ping fall'.format(current_time, ipaddr))
        else:
            print('時間:{} ip地址:{} ping ok'.format(current_time, ipaddr))
    
        fnull.close()
    
    
    if __name__ == '__main__':
        start_time = time.time()
        p = Pool(20)
        res_l = []
        for i in range(1, 256):
            res = p.apply_async(ping_call, args=(i,))
            res_l.append(res)
        for res in res_l:
            res.get()
        print('程序耗時{:.2f}'.format(time.time() - start_time))

    執行結果:
    線程

    blob.png



    線程池異步執行 -- 開啓20個線程

    import os
    import time
    import subprocess
    from concurrent.futures import ThreadPoolExecutor
    def ping_call(num):
        fnull = open(os.devnull, 'w')
        ipaddr = 'ping 192.168.11.' + str(num)
        result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull)
        current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime())
        if result:
            print('時間:{} ip地址:{} ping fall'.format(current_time, ipaddr))
        else:
            print('時間:{} ip地址:{} ping ok'.format(current_time, ipaddr))
        fnull.close()
    
    if __name__ == '__main__':
        start_time = time.time()
        thread_pool = ThreadPoolExecutor(20)
        ret_lst = []
        for i in range(1, 256):
            ret = thread_pool.submit(ping_call, i)
            ret_lst.append(ret)
        thread_pool.shutdown()
        for ret in ret_lst:
            ret.result()
        print('線程池(20)異步-->耗時{:.2f}'.format(time.time() - start_time))

    執行結果:

    blob.png



    協程執行---(執行多個任務,遇到I/O操做就切換)

    使用gevent前,須要pip install gevent

    from gevent import monkey;monkey.patch_all()
    import gevent
    import os
    import time
    import subprocess
    
    def ping_call(num):
        fnull = open(os.devnull, 'w')
        ipaddr = 'ping 192.168.11.' + str(num)
        result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull)
        current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime())
        if result:
            print('時間:{} ip地址:{} ping fall'.format(current_time, ipaddr))
        else:
            print('時間:{} ip地址:{} ping ok'.format(current_time, ipaddr))
        fnull.close()
    
    def asynchronous(): # 異步
        g_l = [gevent.spawn(ping_call, i) for i in range(1, 256)]
        gevent.joinall(g_l)
    
    if __name__ == '__main__':
        start_time = time.time()
        asynchronous()
        print('協程執行-->耗時{:.2f}'.format(time.time() - start_time))

    執行結果:

    blob.png


    遇到I/O操做,協程的效率比進程,線程高不少!

    總結:python中,涉及到I/O阻塞的程序中,使用協程的效率最高


    最後附帶協程池代碼

    gevent.pool

    from gevent import monkey;monkey.patch_all()
    import gevent
    import os
    import time
    import subprocess
    import gevent.pool
    
    def ping_call(num):
        fnull = open(os.devnull, 'w')
        ipaddr = 'ping 192.168.11.' + str(num)
        result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull)
        current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime())
        if result:
            print('時間:{} ip地址:{} ping fall'.format(current_time, ipaddr))
        else:
            print('時間:{} ip地址:{} ping ok'.format(current_time, ipaddr))
        fnull.close()
    
    if __name__ == '__main__':
        start_time = time.time()
        res_l = []
        p = gevent.pool.Pool(100)
        for i in range(1, 256):
            res_l.append(p.spawn(ping_call, i))
        gevent.joinall(res_l)
        print('協程池執行-->耗時{:.2f}'.format(time.time() - start_time))

    執行結果:

    blob.png

     歡迎你們一塊兒來玩好PY,一塊兒交流。QQ羣:198447500

相關文章
相關標籤/搜索