成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

手把手教你用Go語言打造一款簡易TCP端口掃描器

開發 前端
這次呢, 咱們來實現一個簡單的TCP端口掃描器!

[[374779]]

 前言

Hey,大家好呀,我是碼農,星期八。

這次呢, 咱們來實現一個簡單的TCP端口掃描器!

也來體驗一下黑客的風采!

TCP掃描本質

我們在使用TCP進行連接時,需要知道對方機器的ip:port

正常握手

連接成功的話,流程如下。


連接失敗

有正常,就有失敗,如果被連接方關閉的話,流程如下。


如果有防火墻

還有一種可能是,端口開放,但是防火墻攔截,流程如下。


代碼

本質理解之后,就可以開始擼代碼了。

在Go中,我們通常使用net.Dial進行TCP連接

它就兩種情況

  • 成功:返回conn。
  • 失敗:err != nil。

普通版

相對來說,剛開始時,我們可能都不是太膽大,都是先寫原型,也不考慮性能。

代碼

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "net" 
  6.  
  7. func main() { 
  8.     var ip = "192.168.43.34" 
  9.     for i := 21; i <= 120; i++ { 
  10.         var address = fmt.Sprintf("%s:%d", ip, i) 
  11.         conn, err := net.Dial("tcp", address) 
  12.         if err != nil { 
  13.             fmt.Println(address, "是關閉的"
  14.             continue 
  15.         } 
  16.         conn.Close() 
  17.         fmt.Println(address, "打開"
  18.   } 

執行結果


但是這個過程是非常緩慢的。

因為net.Dial如果連接的是未開放的端口,一個端口可能就是20s+,所以,我們為什么學習多線程懂了把!!!

多線程版

上述是通過循環去一個個連接ip:port的,那我們就知道了,在一個個連接的位置,讓多個人去干就好了。

所以,多線程如下。

代碼

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "net" 
  6.     "sync" 
  7.     "time" 
  8.  
  9. func main() { 
  10.  
  11.     var begin =time.Now() 
  12.     //wg 
  13.     var wg sync.WaitGroup 
  14.     //ip 
  15.     var ip = "192.168.99.112" 
  16.     //var ip = "192.168.43.34" 
  17.     //循環 
  18.     for j := 21; j <= 65535; j++ { 
  19.         //添加wg 
  20.         wg.Add(1) 
  21.         go func(i int) { 
  22.             //釋放wg 
  23.             defer wg.Done() 
  24.             var address = fmt.Sprintf("%s:%d", ip, i) 
  25.             //conn, err := net.DialTimeout("tcp", address, time.Second*10) 
  26.             conn, err := net.Dial("tcp", address) 
  27.             if err != nil { 
  28.                 //fmt.Println(address, "是關閉的", err) 
  29.                 return 
  30.             } 
  31.             conn.Close() 
  32.             fmt.Println(address, "打開"
  33.         }(j) 
  34.     //等待wg 
  35.     wg.Wait() 
  36.     var elapseTime = time.Now().Sub(begin
  37.     fmt.Println("耗時:", elapseTime) 

執行結果

 

其實是同時開啟了6W多個線程,去掃描每個ip:port。

所以耗時最長的線程結束的時間,就是程序結束的時間。

感覺還行,20s+掃描完6w多個端口!!!

線程池版

上面我們簡單粗暴的方式為每個ip:port都創建了一個協程。

雖然在Go中,理論上協程開個幾十萬個都沒問題,但是還是有一些壓力的。

所以我們應該采用一種相對節約的方式進行精簡代碼,一般采用線程池方式。

本次使用的線程池包:gohive

地址:https://github.com/loveleshsharma/gohive

簡單介紹


代碼

  1. package main 
  2.  
  3. //線程池方式 
  4. import ( 
  5.     "fmt" 
  6.     "github.com/loveleshsharma/gohive" 
  7.     "net" 
  8.     "sync" 
  9.     "time" 
  10.  
  11. //wg 
  12. var wg sync.WaitGroup 
  13.  
  14. //地址管道,100容量 
  15. var addressChan = make(chan string, 100) 
  16.  
  17. //工人 
  18. func worker() { 
  19.     //函數結束釋放連接 
  20.     defer wg.Done() 
  21.     for { 
  22.         address, ok := <-addressChan 
  23.         if !ok { 
  24.             break 
  25.         } 
  26.         //fmt.Println("address:", address) 
  27.         conn, err := net.Dial("tcp", address) 
  28.         //conn, err := net.DialTimeout("tcp", address, 10) 
  29.         if err != nil { 
  30.             //fmt.Println("close:", address, err) 
  31.             continue 
  32.         } 
  33.         conn.Close() 
  34.         fmt.Println("open:", address) 
  35. func main() { 
  36.     var begin = time.Now() 
  37.     //ip 
  38.     var ip = "192.168.99.112" 
  39.     //線程池大小 
  40.     var pool_size = 70000 
  41.     var pool = gohive.NewFixedSizePool(pool_size) 
  42.  
  43.     //拼接ip:端口 
  44.     //啟動一個線程,用于生成ip:port,并且存放到地址管道種 
  45.     go func() { 
  46.         for port := 1; port <= 65535; port++ { 
  47.             var address = fmt.Sprintf("%s:%d", ip, port) 
  48.             //將address添加到地址管道 
  49.             //fmt.Println("<-:",address) 
  50.             addressChan <- address 
  51.         } 
  52.         //發送完關閉 addressChan 管道 
  53.         close(addressChan) 
  54. }() 
  55.     //啟動pool_size工人,處理addressChan種的每個地址 
  56.     for work := 0; work < pool_size; work++ { 
  57.         wg.Add(1) 
  58.         pool.Submit(worker) 
  59.     //等待結束 
  60.     wg.Wait() 
  61.     //計算時間 
  62.     var elapseTime = time.Now().Sub(begin
  63.     fmt.Println("耗時:", elapseTime) 

執行結果


我設置的線程池大小是7w個,所以也是一下子開啟6w多個協程的,但是我們已經可以進行線程大小約束了。

假設現在有這樣的去求,有100個ip,需要掃描每個ip開放的端口,如果采用簡單粗暴開線程的方式.

那就是100+65535=6552300,600多w個線程,還是比較消耗內存的,可能系統就會崩潰,如果采用線程池方式。

將線程池控制在50w個,或許情況就會好很多。

但是有一點的是,在Go中,線程池通常需要配合chan使用,可能需要不錯的基礎。

總結

本篇更偏向于樂趣篇,了解一下好玩的玩意。

其實還可以通過net.DialTimeout連接ip:port,這個可以設置超時時間,比如超時5s就判定端口未開放。

此處就不做舉例了。

咱們主要使用三種方式來實現功能。

  • 正常版,沒有并發,速度很慢。
  • 多協程版,并發,性能很高,但是協程太多可能會崩潰。
  • 協程池版,并發,性能高,協程數量可控。

通常情況下,如果基礎可以,更推薦使用協程池方式。

用微笑告訴別人,今天的我比昨天強,今后也一樣。

 

責任編輯:姜華 來源: Go語言進階學習
相關推薦

2024-01-07 20:00:27

2021-01-21 06:04:55

Go語言TCP目錄生成器

2023-05-22 10:04:24

2021-02-01 08:41:06

Java考試系統

2021-02-04 15:52:46

Java考試系統

2017-09-14 09:09:04

php應用LibreOfficeWord轉HTML

2021-01-04 09:55:26

Java移動互聯網

2021-01-05 09:04:20

Javatxt文件

2022-02-17 10:26:17

JavaScript掃雷游戲前端

2021-11-01 10:26:07

CanvasAPI畫布技術HTML5

2021-12-30 08:56:57

Python摸魚倒計界面Python基礎

2021-08-13 09:01:31

Python小游戲Python基礎

2022-10-19 14:30:59

2022-01-24 11:02:27

PySimpleGUPython計算器

2021-08-09 13:31:25

PythonExcel代碼

2022-08-04 10:39:23

Jenkins集成CD

2011-03-28 16:14:38

jQuery

2021-02-06 14:55:05

大數據pandas數據分析

2021-02-04 09:00:57

SQLDjango原生

2022-06-30 16:10:26

Python計時器裝飾器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一二三区 | 羞羞羞视频 | 成人性视频免费网站 | 日本激情视频在线播放 | 欧美精品第一页 | 久草青青草 | 成人欧美一区二区三区黑人孕妇 | 爱爱爱av | 久久亚洲一区 | 成人av在线播放 | 日本天堂一区二区 | 黄a大片| 青草视频在线 | 国产精品一区二区av | 一区二区三区四区av | 在线黄av | 日韩欧美一区二区三区免费看 | 亚洲一区久久 | 一级大黄色片 | 久久精品国产精品青草 | 日韩精品一区二区三区四区视频 | 一区二区三区四区在线播放 | 国产成人精品综合 | 日本一区二区三区免费观看 | 亚洲精品久久久久中文字幕欢迎你 | 亚洲精品免费视频 | 欧美中文字幕 | 成人超碰 | 免费精品视频 | 国内精品免费久久久久软件老师 | 视频在线一区 | 夜夜摸天天操 | 精品久久久久久久 | 亚洲精品9999 | 视频在线一区 | 成人在线播放 | 黄色一级大片在线免费看产 | 欧美极品在线观看 | 日韩精品免费 | 黄免费观看视频 | 久久久久久久久久一区 |