您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么用Go語(yǔ)言打造一款簡(jiǎn)易TCP端口掃描器”,在日常操作中,相信很多人在怎么用Go語(yǔ)言打造一款簡(jiǎn)易TCP端口掃描器問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么用Go語(yǔ)言打造一款簡(jiǎn)易TCP端口掃描器”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
TCP掃描本質(zhì)
我們?cè)谑褂肨CP進(jìn)行連接時(shí),需要知道對(duì)方機(jī)器的ip:port
正常握手
連接成功的話,流程如下。
連接失敗
有正常,就有失敗,如果被連接方關(guān)閉的話,流程如下。
如果有防火墻
還有一種可能是,端口開(kāi)放,但是防火墻攔截,流程如下。
代碼
本質(zhì)理解之后,就可以開(kāi)始擼代碼了。
在Go中,我們通常使用net.Dial進(jìn)行TCP連接。
它就兩種情況
成功:返回conn。
失敗:err != nil。
普通版
相對(duì)來(lái)說(shuō),剛開(kāi)始時(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, "打開(kāi)") } }
執(zhí)行結(jié)果
但是這個(gè)過(guò)程是非常緩慢的。
因?yàn)閚et.Dial如果連接的是未開(kāi)放的端口,一個(gè)端口可能就是20s+,所以,我們?yōu)槭裁磳W(xué)習(xí)多線程懂了把!!!
多線程版
上述是通過(guò)循環(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, "打開(kāi)") }(j) } //等待wg wg.Wait() var elapseTime = time.Now().Sub(begin) fmt.Println("耗時(shí):", elapseTime) }
執(zhí)行結(jié)果
其實(shí)是同時(shí)開(kāi)啟了6W多個(gè)線程,去掃描每個(gè)ip:port。
所以耗時(shí)最長(zhǎng)的線程結(jié)束的時(shí)間,就是程序結(jié)束的時(shí)間。
感覺(jué)還行,20s+掃描完6w多個(gè)端口!!!
線程池版
上面我們簡(jiǎn)單粗暴的方式為每個(gè)ip:port都創(chuàng)建了一個(gè)協(xié)程。
雖然在Go中,理論上協(xié)程開(kāi)個(gè)幾十萬(wàn)個(gè)都沒(méi)問(wèn)題,但是還是有一些壓力的。
所以我們應(yīng)該采用一種相對(duì)節(jié)約的方式進(jìn)行精簡(jiǎn)代碼,一般采用線程池方式。
本次使用的線程池包:gohive
地址:https://github.com/loveleshsharma/gohive
簡(jiǎn)單介紹
代碼
package main //線程池方式 import ( "fmt" "github.com/loveleshsharma/gohive" "net" "sync" "time" ) //wg var 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:端口 //啟動(dòng)一個(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) }() //啟動(dòng)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è),所以也是一下子開(kāi)啟6w多個(gè)協(xié)程的,但是我們已經(jīng)可以進(jìn)行線程大小約束了。
假設(shè)現(xiàn)在有這樣的去求,有100個(gè)ip,需要掃描每個(gè)ip開(kāi)放的端口,如果采用簡(jiǎn)單粗暴開(kāi)線程的方式.
那就是100+65535=6552300,600多w個(gè)線程,還是比較消耗內(nèi)存的,可能系統(tǒng)就會(huì)崩潰,如果采用線程池方式。
將線程池控制在50w個(gè),或許情況就會(huì)好很多。
但是有一點(diǎn)的是,在Go中,線程池通常需要配合chan使用,可能需要不錯(cuò)的基礎(chǔ)。
到此,關(guān)于“怎么用Go語(yǔ)言打造一款簡(jiǎn)易TCP端口掃描器”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。