实例探究Python以并发方式编写高性能端口扫描器的方法


Posted in Python onJune 14, 2016

关于端口扫描器
端口扫描工具(Port Scanner)指用于探测服务器或主机开放端口情况的工具。常被计算机管理员用于确认安全策略,同时被攻击者用于识别目标主机上的可运作的网络服务。

端口扫描定义是客户端向一定范围的服务器端口发送对应请求,以此确认可使用的端口。虽然其本身并不是恶意的网络活动,但也是网络攻击者探测目标主机服务,以利用该服务的已知漏洞的重要手段。端口扫描的主要用途仍然只是确认远程机器某个服务的可用性。

扫描多个主机以获取特定的某个端口被称为端口清扫(Portsweep),以此获取特定的服务。例如,基于SQL服务的计算机蠕虫就会清扫大量主机的同一端口以在 1433 端口上建立TCP连接。

Python实现

端口扫描器原理很简单,无非就是操作socket,能connect就认定这个端口开放着。

import socket 
def scan(port): 
  s = socket.socket() 
  if s.connect_ex(('localhost', port)) == 0: 
    print port, 'open' 
  s.close() 
if __name__ == '__main__': 
  map(scan,range(1,65536))

这样一个最简单的端口扫描器出来了。
等等喂,半天都没反应,那是因为socket是阻塞的,每次连接要等很久才超时。
我们自己给它加上的超时。

s.settimeout(0.1)

再跑一遍,感觉快多了。

多线程版本

import socket 
import threading 
def scan(port): 
  s = socket.socket() 
  s.settimeout(0.1) 
  if s.connect_ex(('localhost', port)) == 0: 
    print port, 'open' 
  s.close() 
 
if __name__ == '__main__': 
  threads = [threading.Thread(target=scan, args=(i,)) for i in xrange(1,65536)] 
  map(lambda x:x.start(),threads)

运行一下,哇,好快,快到抛出错误了。thread.error: can't start new thread。
想一下,这个进程开启了65535个线程,有两种可能,一种是超过最大线程数了,一种是超过最大socket句柄数了。在linux可以通过ulimit来修改。
如果不修改最大限制,怎么用多线程不报错呢?
加个queue,变成生产者-消费者模式,开固定线程。

多线程+队列版本

import socket 
import threading 
from Queue import Queue 
def scan(port): 
  s = socket.socket() 
  s.settimeout(0.1) 
  if s.connect_ex(('localhost', port)) == 0: 
    print port, 'open' 
  s.close() 
 
def worker(): 
  while not q.empty(): 
    port = q.get() 
    try: 
      scan(port) 
    finally: 
      q.task_done() 
 
if __name__ == '__main__': 
  q = Queue() 
  map(q.put,xrange(1,65535)) 
  threads = [threading.Thread(target=worker) for i in xrange(500)] 
  map(lambda x:x.start(),threads) 
  q.join()

这里开500个线程,不停的从队列取任务来做。

multiprocessing+队列版本
总不能开65535个进程吧?还是用生产者消费者模式

import multiprocessing 
def scan(port): 
  s = socket.socket() 
  s.settimeout(0.1) 
  if s.connect_ex(('localhost', port)) == 0: 
    print port, 'open' 
  s.close() 
 
def worker(q): 
  while not q.empty(): 
    port = q.get() 
    try: 
      scan(port) 
    finally: 
      q.task_done() 
 
if __name__ == '__main__': 
  q = multiprocessing.JoinableQueue() 
  map(q.put,xrange(1,65535)) 
  jobs = [multiprocessing.Process(target=worker, args=(q,)) for i in xrange(100)] 
  map(lambda x:x.start(),jobs)

注意这里把队列作为一个参数传入到worker中去,因为是process safe的queue,不然会报错。
还有用的是JoinableQueue(),顾名思义就是可以join()的。

gevent的spawn版本

from gevent import monkey; monkey.patch_all(); 
import gevent 
import socket 
... 
if __name__ == '__main__': 
  threads = [gevent.spawn(scan, i) for i in xrange(1,65536)] 
  gevent.joinall(threads)

注意monkey patch必须在被patch的东西之前import,不然会Exception KeyError.比如不能先import threading,再monkey patch.

gevent的Pool版本

from gevent import monkey; monkey.patch_all(); 
import socket 
from gevent.pool import Pool 
... 
if __name__ == '__main__': 
  pool = Pool(500) 
  pool.map(scan,xrange(1,65536)) 
  pool.join()

concurrent.futures版本

import socket 
from Queue import Queue 
from concurrent.futures import ThreadPoolExecutor 
... 
if __name__ == '__main__': 
  q = Queue() 
  map(q.put,xrange(1,65536)) 
  with ThreadPoolExecutor(max_workers=500) as executor: 
    for i in range(500): 
      executor.submit(worker,q)
Python 相关文章推荐
python实现的一只从百度开始不断搜索的小爬虫
Aug 13 Python
使用Protocol Buffers的C语言拓展提速Python程序的示例
Apr 16 Python
python 中的divmod数字处理函数浅析
Oct 17 Python
Python爬虫实例爬取网站搞笑段子
Nov 08 Python
tensorflow学习笔记之简单的神经网络训练和测试
Apr 15 Python
Python编写一个优美的下载器
Apr 15 Python
Tensorflow 训练自己的数据集将数据直接导入到内存
Jun 19 Python
python读取一个目录下所有txt里面的内容方法
Jun 23 Python
python3 拼接字符串的7种方法
Sep 12 Python
python程序封装为win32服务的方法
Mar 07 Python
python智联招聘爬虫并导入到excel代码实例
Sep 09 Python
Python3 中sorted() 函数的用法
Mar 24 Python
Python使用dis模块把Python反编译为字节码的用法详解
Jun 14 #Python
Python的Flask框架中使用Flask-Migrate扩展迁移数据库的教程
Jun 14 #Python
Python的Flask框架中使用Flask-SQLAlchemy管理数据库的教程
Jun 14 #Python
全面了解Python的getattr(),setattr(),delattr(),hasattr()
Jun 14 #Python
浅谈python中的getattr函数 hasattr函数
Jun 14 #Python
深入解析Python中的线程同步方法
Jun 14 #Python
详解Python中的Descriptor描述符类
Jun 14 #Python
You might like
php对文件进行hash运算的方法
2015/04/03 PHP
php实现上传图片文件代码
2015/07/19 PHP
使用Thinkphp框架开发移动端接口
2015/08/05 PHP
laravel批量生成假数据的方法
2019/10/09 PHP
javaScript 判断字符串是否为数字的简单方法
2009/07/25 Javascript
再谈javascript 动态添加样式规则 W3C校检
2009/12/25 Javascript
JSON 教程 json入门学习笔记
2020/09/22 Javascript
jquery tab插件制作实现代码
2010/06/22 Javascript
js里怎么取select标签里的值并修改
2012/12/10 Javascript
利用jQuery的deferred对象实现异步按顺序加载JS文件
2013/03/17 Javascript
Angular2使用Guard和Resolve进行验证和权限控制
2017/04/24 Javascript
解决ng-repeat产生的ng-model中取不到值的问题
2018/10/02 Javascript
修改layui的后台模板的左侧导航栏可以伸缩的方法
2019/09/10 Javascript
SpringBoot+Vue开发之Login校验规则、实现登录和重置事件
2020/10/19 Javascript
python BeautifulSoup使用方法详解
2013/11/21 Python
十个Python练手的实战项目,学会这些Python就基本没问题了(推荐)
2019/04/26 Python
Flask框架工厂函数用法实例分析
2019/05/25 Python
PIL对上传到Django的图片进行处理并保存的实例
2019/08/07 Python
最小二乘法及其python实现详解
2020/02/24 Python
Python通过Schema实现数据验证方式
2020/11/12 Python
python反爬虫方法的优缺点分析
2020/11/25 Python
使用CSS3实现圆角,阴影,透明
2014/12/23 HTML / CSS
探索HTML5本地存储功能运用技巧
2016/03/02 HTML / CSS
英国定做窗帘和纺织品面料一站式商店:Dekoria
2018/08/29 全球购物
生产厂厂长岗位职责
2013/12/25 职场文书
如何写好升职自荐信
2014/01/06 职场文书
护理专业大学生自我推荐信
2014/01/25 职场文书
2014年道德讲堂实施方案
2014/03/05 职场文书
水污染治理工程专业求职信
2014/06/14 职场文书
中职生求职信
2014/07/01 职场文书
学校总务处领导干部个人对照检查材料思想汇报
2014/10/06 职场文书
2014年工会工作总结
2014/11/12 职场文书
2015年世界环境日活动总结
2015/02/11 职场文书
培根随笔读书笔记
2015/07/01 职场文书
一文读懂go中semaphore(信号量)源码
2021/04/03 Golang
Python中基础数据类型 set集合知识点总结
2021/08/02 Python