Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go并发端口扫描器

基于Go语言实现一个并发端口扫描器

作者:程序员爱钓鱼

这篇文章主要介绍了如何使用 Go 实现一个并发端口扫描器,通过 Goroutine 并发扫描多个端口,极大地提升端口扫描的效率,本文不仅讲解了如何使用 Go 的并发特性,还涉及了如何处理超时和错误,保证端口扫描的健壮性和效率,需要的朋友可以参考下

一、实战背景

端口扫描器是网络安全领域常用的工具,它通过对目标主机的端口进行扫描,检测目标设备是否开放某些服务端口(如 HTTP、FTP、SSH 等)。常见的端口扫描场景包括:

传统的端口扫描使用串行方式,一个端口一个端口地检查,速度非常慢。而 Go 的并发编程可以极大地提升扫描效率。

二、实战目标

我们将实现一个并发端口扫描器,具备以下功能:

  1. 输入目标主机 IP 和端口范围
  2. 使用并发扫描多个端口
  3. 输出每个端口的开放状态
  4. 使用超时机制控制扫描时间,避免阻塞

三、完整代码实现

1. 扫描器实现(scanner.go)

package main

import (
    "fmt"
    "net"
    "strconv"
    "sync"
    "time"
)

func scanPort(ip string, port int, wg *sync.WaitGroup, resultCh chan<- string) {
    defer wg.Done()

    address := fmt.Sprintf("%s:%d", ip, port)
    conn, err := net.DialTimeout("tcp", address, 1*time.Second) // 设置连接超时时间
    if err != nil {
        resultCh <- fmt.Sprintf("端口 %d: 关闭", port)
        return
    }
    conn.Close()
    resultCh <- fmt.Sprintf("端口 %d: 开放", port)
}

func main() {
    var wg sync.WaitGroup
    resultCh := make(chan string, 100) // 创建带缓冲的 Channel,缓冲区大小为 100

    fmt.Print("请输入目标 IP 地址: ")
    var ip string
    fmt.Scanln(&ip)

    fmt.Print("请输入端口范围(例如:80 100): ")
    var startPort, endPort int
    fmt.Scanln(&startPort, &endPort)

    // 扫描指定范围的端口
    for port := startPort; port <= endPort; port++ {
        wg.Add(1)
        go scanPort(ip, port, &wg, resultCh)
    }

    // 等待所有扫描任务完成并关闭 Channel
    go func() {
        wg.Wait()
        close(resultCh)
    }()

    // 打印扫描结果
    fmt.Println("\n扫描结果:")
    for result := range resultCh {
        fmt.Println(result)
    }
}

四、运行方式

执行端口扫描器

go run scanner.go

输入示例:

请输入目标 IP 地址: 192.168.1.1
请输入端口范围(例如:80 100): 80 90

输出示例:

扫描结果:
端口 80: 开放
端口 81: 关闭
端口 82: 关闭
端口 83: 关闭
端口 84: 开放
端口 85: 关闭
端口 86: 开放
端口 87: 关闭
端口 88: 关闭
端口 89: 开放
端口 90: 关闭

五、关键技术点解析

1. 使用 Goroutine 并发扫描端口

每个端口的扫描任务都是由独立的 Goroutine 执行的。这样可以最大化利用 CPU 核心,实现端口扫描的并发化。

go scanPort(ip, port, &wg, resultCh)

2. 使用 sync.WaitGroup 等待所有 Goroutine 完成

WaitGroup 用来等待所有扫描任务完成,确保在关闭结果通道之前所有扫描任务已经结束。

var wg sync.WaitGroup
wg.Add(1)

3. 使用 net.DialTimeout 设置连接超时

DialTimeout 可以在指定的超时时间内完成连接,如果超时则返回错误。我们在这里设置了 1 秒的超时。

conn, err := net.DialTimeout("tcp", address, 1*time.Second)

4. 使用 channel 收集扫描结果

通过 Channel 传递每个端口的扫描结果,避免了主线程和 Goroutine 之间的数据竞争问题。

resultCh <- fmt.Sprintf("端口 %d: 开放", port)

5. 缓存扫描结果并打印

使用带缓冲的 Channel resultCh 存储扫描结果。所有任务完成后,我们关闭通道并打印扫描结果。

go func() {
    wg.Wait()
    close(resultCh)
}()

六、优化和扩展方向

优化方向说明
控制并发数量使用令牌桶算法(Token Bucket)或 sem 控制并发扫描的 Goroutine 数量
支持输入多个目标 IP扩展支持一次扫描多个 IP 地址
扫描端口的协议支持不仅支持 TCP 端口扫描,还可支持 UDP 扫描
日志记录将扫描结果输出到日志文件,便于后期分析
进度条显示添加扫描进度显示,提升用户体验
智能端口扫描根据常见端口列表(如 80、443、21 等)进行扫描

七、小结

通过本篇案例,你学会了如何用 Go 实现一个并发端口扫描器,掌握了以下关键技术:

这个并发端口扫描器可以帮助你在网络安全和系统维护中快速诊断目标主机的开放端口。通过优化,您还可以将其扩展成更完整的网络扫描工具。

以上就是基于Go语言实现一个并发端口扫描器的详细内容,更多关于Go并发端口扫描器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文