<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 556字,需瀏覽 2分鐘

           ·

          2021-01-13 09:47

          點(diǎn)擊上方“Go語言進(jìn)階學(xué)習(xí)”,進(jìn)行關(guān)注

          回復(fù)“Go語言”即可獲贈從入門到進(jìn)階共10本電子書

          含光混世貴無名,何用孤高比云月?

          前言

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

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

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

          TCP掃描本質(zhì)

          我們在使用TCP進(jìn)行連接時(shí),需要知道對方機(jī)器ip:port

          正常握手

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

          連接失敗

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

          如果有防火墻

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

          代碼

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

          在Go中,我們通常使用net.Dial進(jìn)行TCP連接。

          它就兩種情況

          • 成功:返回conn。

          • 失敗:err != nil。

          普通版

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

          代碼

          package main
          import ( "fmt" "net")
          func main() { var ip = "192.168.43.34" for i := 21; i <= 120; i++ { var address = fmt.Sprintf("%s:%d", ip, i) conn, err := net.Dial("tcp", address) if err != nil { fmt.Println(address, "是關(guān)閉的") continue } conn.Close() fmt.Println(address, "打開") }}

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

          但是這個(gè)過程是非常緩慢的。

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

          多線程版

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

          所以,多線程如下。

          代碼

          package main
          import ( "fmt" "net" "sync" "time")
          func main() {
          var begin =time.Now() //wg var wg sync.WaitGroup //ip var ip = "192.168.99.112" //var ip = "192.168.43.34" //循環(huán) for j := 21; j <= 65535; j++ { //添加wg wg.Add(1) go func(i int) { //釋放wg defer wg.Done() var address = fmt.Sprintf("%s:%d", ip, i) //conn, err := net.DialTimeout("tcp", address, time.Second*10) conn, err := net.Dial("tcp", address) if err != nil { //fmt.Println(address, "是關(guān)閉的", err) return } conn.Close() fmt.Println(address, "打開") }(j)} //等待wg wg.Wait() var elapseTime = time.Now().Sub(begin) fmt.Println("耗時(shí):", elapseTime)}

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

          其實(shí)是同時(shí)開啟了6W多個(gè)線程,去掃描每個(gè)ip:port

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

          感覺還行,20s+掃描完6w多個(gè)端口!??!

          線程池版

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

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

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


          本次使用的線程池包:gohive

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

          簡單介紹

          代碼

          package main
          //線程池方式import ( "fmt" "github.com/loveleshsharma/gohive" "net" "sync" "time")
          //wgvar wg sync.WaitGroup
          //地址管道,100容量var addressChan = make(chan string, 100)
          //工人func worker() { //函數(shù)結(jié)束釋放連接 defer wg.Done() for { address, ok := <-addressChan if !ok { break } //fmt.Println("address:", address) conn, err := net.Dial("tcp", address) //conn, err := net.DialTimeout("tcp", address, 10) if err != nil { //fmt.Println("close:", address, err) continue } conn.Close() fmt.Println("open:", address)}}func main() { var begin = time.Now() //ip var ip = "192.168.99.112" //線程池大小 var pool_size = 70000 var pool = gohive.NewFixedSizePool(pool_size)
          //拼接ip:端口 //啟動一個(gè)線程,用于生成ip:port,并且存放到地址管道種 go func() { for port := 1; port <= 65535; port++ { var address = fmt.Sprintf("%s:%d", ip, port) //將address添加到地址管道 //fmt.Println("<-:",address) addressChan <- address } //發(fā)送完關(guān)閉 addressChan 管道 close(addressChan)}() //啟動pool_size工人,處理addressChan種的每個(gè)地址 for work := 0; work < pool_size; work++ { wg.Add(1) pool.Submit(worker)} //等待結(jié)束 wg.Wait() //計(jì)算時(shí)間 var elapseTime = time.Now().Sub(begin) fmt.Println("耗時(shí):", elapseTime)}

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

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


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

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

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

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

          總結(jié)

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

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

          此處就不做舉例了。

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

          • 正常版,沒有并發(fā),速度很慢。

          • 多協(xié)程版,并發(fā),性能很高,但是協(xié)程太多可能會崩潰。

          • 協(xié)程池版,并發(fā),性能高,協(xié)程數(shù)量可控。

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

          如果在操作過程中有任何問題,記得下面留言,我們看到會第一時(shí)間解決問題。

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

          我是碼農(nóng)星期八,如果覺得還不錯(cuò),記得動手點(diǎn)贊一下哈。

          感謝你的觀看。


          如果你覺得文章還可以,記得點(diǎn)贊留言支持我們哈。感謝你的閱讀,有問題請記得在下方留言噢~

          想學(xué)習(xí)更多關(guān)于Python的知識,可以參考學(xué)習(xí)網(wǎng)址:http://pdcfighting.com/,點(diǎn)擊閱讀原文,可以直達(dá)噢~

          想了解更多關(guān)于Go的知識,請前往:http://pdcfighting.com/

          -------------------?End?-------------------

          往期精彩文章推薦:

          歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持

          想加入Go學(xué)習(xí)群請?jiān)诤笈_回復(fù)【入群

          萬水千山總是情,點(diǎn)個(gè)【在看】行不行

          瀏覽 52
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美女在线扣穴 | 成人网站在线视频三级 | 人人操操| 免费看一区二区三区四区 | 亚洲免费网站在线观看 |