国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

實例探究Python以并發方式編寫高性能端口掃描器的方法

2019-11-25 16:43:52
字體:
來源:轉載
供稿:網友

關于端口掃描器
端口掃描工具(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) 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 漯河市| 屏南县| 乐业县| 安龙县| 策勒县| 南康市| 临漳县| 车险| 隆昌县| 汾西县| 盐山县| 林甸县| 通江县| 志丹县| 手游| 宣化县| 鸡泽县| 成都市| 松江区| 保德县| 建德市| 洛隆县| 垣曲县| 南雄市| 仲巴县| 淮南市| 普宁市| 三原县| 青川县| 宁明县| 聊城市| 乐陵市| 林口县| 保山市| 吉安市| 玛沁县| 巫溪县| 峨眉山市| 本溪市| 萍乡市| 元氏县|