日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
手把手教你用Go語言打造一款簡易TCP端口掃描器

 前言

創(chuàng)新互聯(lián)公司是一家網(wǎng)站設(shè)計公司,集創(chuàng)意、互聯(lián)網(wǎng)應(yīng)用、軟件技術(shù)為一體的創(chuàng)意網(wǎng)站建設(shè)服務(wù)商,主營產(chǎn)品:成都響應(yīng)式網(wǎng)站建設(shè)、品牌網(wǎng)站制作、成都全網(wǎng)營銷推廣。我們專注企業(yè)品牌在網(wǎng)站中的整體樹立,網(wǎng)絡(luò)互動的體驗,以及在手機等移動端的優(yōu)質(zhì)呈現(xiàn)。成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、移動互聯(lián)產(chǎn)品、網(wǎng)絡(luò)運營、VI設(shè)計、云產(chǎn)品.運維為核心業(yè)務(wù)。為用戶提供一站式解決方案,我們深知市場的競爭激烈,認真對待每位客戶,為客戶提供賞析悅目的作品,網(wǎng)站的價值服務(wù)。

Hey,大家好呀,我是碼農(nóng),星期八。

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

也來體驗一下黑客的風(fēng)采!

TCP掃描本質(zhì)

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

正常握手

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

連接失敗

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

如果有防火墻

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

代碼

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

在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, "是關(guān)閉的") 
  14.             continue 
  15.         } 
  16.         conn.Close() 
  17.         fmt.Println(address, "打開") 
  18.   } 

執(zhí)行結(jié)果

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

因為net.Dial如果連接的是未開放的端口,一個端口可能就是20s+,所以,我們?yōu)槭裁磳W(xué)習(xí)多線程懂了把!!!

多線程版

上述是通過循環(huán)去一個個連接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.     //循環(huán) 
  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, "是關(guān)閉的", 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) 

執(zhí)行結(jié)果

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

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

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

線程池版

上面我們簡單粗暴的方式為每個ip:port都創(chuàng)建了一個協(xié)程。

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

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

本次使用的線程池包: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.     //函數(shù)結(jié)束釋放連接 
  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.         //發(fā)送完關(guān)閉 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.     //等待結(jié)束 
  60.     wg.Wait() 
  61.     //計算時間 
  62.     var elapseTime = time.Now().Sub(begin) 
  63.     fmt.Println("耗時:", elapseTime) 

執(zhí)行結(jié)果

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

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

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

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

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

總結(jié)

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

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

此處就不做舉例了。

咱們主要使用三種方式來實現(xiàn)功能。

  • 正常版,沒有并發(fā),速度很慢。
  • 多協(xié)程版,并發(fā),性能很高,但是協(xié)程太多可能會崩潰。
  • 協(xié)程池版,并發(fā),性能高,協(xié)程數(shù)量可控。

通常情況下,如果基礎(chǔ)可以,更推薦使用協(xié)程池方式。

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


分享題目:手把手教你用Go語言打造一款簡易TCP端口掃描器
轉(zhuǎn)載來源:http://www.5511xx.com/article/dhcgjpg.html