利用python实现IP扫描

发布时间:2019-09-21 11:10:07编辑:auto阅读(1343)

      需求:写一个脚本,判断192.168.11.0/24网络里,当前在线ip有哪些?

      知识点:

      1 使用subprocess模块,来调用系统命令,执行ping 192.168.11.xxx 命令

      2 调用系统命令执行ping命令的时候,会有返回值(ping的结果),需要用到stdout=fnull, stderr=fnull方法,屏蔽系统执行命令的返回值

       

      常规版本(代码)

      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()

      执行效果:

      blob.png


      上面的执行速度非常慢,怎么能让程序执行速度快起来?

      python提供了进程,线程,协程。分别用这三个对上面代码改进,提高执行效率,测试一波效率


      进程池异步执行 -- 开启20个进程

      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

关键字