深入详解如何使用Go实现端口扫描器

 更新时间:2025年11月18日 09:43:54   作者:Mgx  
这篇文章主要为大家详细介绍了深如何使用Go语言实现一个简单的端口扫描器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

免责声明:本文仅供学习交流,请勿用于非 法扫描他人设备。

一、故事从一个"好奇"开始

某天深夜,我盯着路由器发呆:"嘿,我家这台小铁盒子,到底开了哪些端口?会不会有神秘服务在偷偷运行?"

于是——我决定写个工具,批量敲门:

"你好,请问 1 号端口在家吗?"

"2 号呢?"

"……65535 号?你睡了吗?"

结果发现:

22 号(SSH)说:"密码不对,走开!" 80 号(HTTP)热情招呼:"欢迎访问我的 404 页面!" 而 1433 号(MSSQL)……根本没人应门 😢 今天,我就带你用 Go 语言,100 行代码实现一个高并发 TCP 端口扫描器,轻松探查目标主机哪些"门"是开着的!

二、核心思路:生产者 + 消费者模型

我们的程序就像一家快递公司:

老板(main):把 65535 个包裹(端口任务)放进仓库(channel)。 快递员(goroutine):100 个(或你指定的数量)工人同时取件、送货(尝试连接)。 成功送达? → 记录日志:"XX 端口有人签收!" 没人收? → 默默扔掉,继续下一件。 整个过程又快又稳,全靠 Go 的并发神器:goroutine + channel!

三、关键 Go 知识点解析

1. goroutine:轻量级线程

scanWorker() // 启动一个后台任务
  • 不是操作系统线程,而是 Go 调度器管理的"绿色线程"。
  • 启动成本极低,100 个并发轻轻松松。

2. channel:安全通信管道

taskCh := make(chan string, 1000)
  • 带缓冲的 channel,作为任务队列。
  • 多个 goroutine 安全地从中读取任务,无需加锁!

3. sync.WaitGroup:等待所有任务完成

wg.Add(1)
defer wg.Done()
wg.Wait()
  • 主 goroutine 会卡在 Wait(),直到所有 worker 执行完毕。
  • 避免程序提前退出。

4. net.DialTimeout:带超时的 TCP 连接

net.DialTimeout("tcp", "192.168.1.1:80", 1*time.Second)
  • 如果 1 秒内连不上,就放弃,避免卡死。
  • 是端口扫描的核心 API!

5. 命令行参数解析

ip := os.Args[1]
threads := os.Args[2]
  • 简单直接,适合小型工具。
  • (复杂场景可用 flag 或 cobra 库)

6. 错误处理 & 输入校验

  • 用 net.ParseIP 验证 IP 格式。
  • 用 strconv.Atoi 转换线程数,并检查范围。
  • 用户输错?友好提示,优雅退出。

四、运行效果预览

$ ./portscanner 127.0.0.1 50
2025-11-08 22:19:16:330076[main.go:75][INFO]开放的服务:192.168.1.1 [192.168.1.1:25]
2025-11-08 22:19:16:334967[main.go:75][INFO]开放的服务:192.168.1.1 [192.168.1.1:80]
2025-11-08 22:19:17:328821[main.go:75][INFO]开放的服务:192.168.1.1 [192.168.1.1:110]
2025-11-08 22:19:20:333560[main.go:75][INFO]开放的服务:192.168.1.1 [192.168.1.1:443]
...
扫描完成。

同时,日志还会自动保存到 runlog/ 目录,方便后续分析!

五、完整源码奉上!

依赖:github.com/Jjmgx/mgxlog(一个简单的日志库)

安装命令:go get github.com/Jjmgx/mgxlog

package main

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

	"github.com/Jjmgx/mgxlog"
)

var wg sync.WaitGroup
var taskCh = make(chan string, 1000) // 任务通道:ip:port

var logger, _ = mgxlog.NewMgxLog("runlog/", 10*1024*1024, 100, 3, 1000)

func main() {
	if len(os.Args) != 3 {
		fmt.Fprintf(os.Stderr, "用法: %s <IP地址> <线程数>\n", os.Args[0])
		os.Exit(1)
	}

	ip := os.Args[1]
	threadStr := os.Args[2]

	// 验证 IP 格式
	if net.ParseIP(ip) == nil {
		fmt.Fprintf(os.Stderr, "错误: 无效的 IP 地址 '%s'\n", ip)
		os.Exit(1)
	}

	// 解析线程数
	threads, err := strconv.Atoi(threadStr)
	if err != nil || threads <= 0 || threads > 10000 {
		fmt.Fprintf(os.Stderr, "错误: 线程数必须是 1~10000 之间的整数\n")
		os.Exit(1)
	}

	// 启动 worker goroutines
	for i := 0; i < threads; i++ {
		wg.Add(1)
		go scanWorker()
	}

	// 生产者:生成所有端口任务(1~65535)
	go func() {
		defer close(taskCh)
		for port := 1; port <= 65535; port++ {
			taskCh <- fmt.Sprintf("%s:%d", ip, port)
		}
	}()

	wg.Wait()
	fmt.Println("扫描完成。")
}

func scanWorker() {
	defer wg.Done()
	for ipPort := range taskCh {
		scanPort(ipPort)
	}
}

func scanPort(ipPort string) {
	conn, err := net.DialTimeout("tcp", ipPort, 1*time.Second)
	if err != nil {
		return // 连不上?下一个!
	}
	defer conn.Close()

	addr := conn.RemoteAddr().(*net.TCPAddr)
	msg := fmt.Sprintf("开放的服务:%s [%s:%d]", addr.IP, addr.IP, addr.Port)
	logger.Info(msg)
	fmt.Println(msg) // 控制台也输出,看得爽!
}

六、结语:技术无罪,滥用有责

这个小工具展示了 Go 在网络编程和并发处理上的强大能力。你可以在此基础上扩展:

  • 支持端口范围(如 80,443,8000-9000)
  • 识别服务类型(发送 HTTP/TDS/Redis 协议探测包)
  • 输出 JSON / CSV 报告

但请记住:好奇心要有,边界感更要有。只扫描你拥有权限的设备,做一名负责任的"数字侦探"!

到此这篇关于深入详解如何使用Go实现端口扫描器的文章就介绍到这了,更多相关Go端口扫描器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 四种Golang实现middleware框架的方式小结

    四种Golang实现middleware框架的方式小结

    middleware是一般框架里面常用的形式,比如web框架、rpc框架等,本文为大家详细介绍了四种实现middleawre的方式,感兴趣的可以了解一下
    2024-03-03
  • Go语言的接口详解

    Go语言的接口详解

    这篇文章主要介绍了go语言的接口,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧,希望能够给你带来帮助
    2021-10-10
  • Go语言中的数据竞争模式详解

    Go语言中的数据竞争模式详解

    这篇文章主要介绍了Go语言中的数据竞争模式详解,主要基于在Uber的Go monorepo中发现的各种数据竞争模式,分析了其背后的原因与分类,需要的朋友可以参考一下
    2022-07-07
  • go Antlr重构脚本解释器实现示例

    go Antlr重构脚本解释器实现示例

    这篇文章主要为大家介绍了go Antlr重构脚本解释器实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 深入理解go缓存库freecache的使用

    深入理解go缓存库freecache的使用

    go开发缓存场景一般使用map或者缓存框架,为了线程安全会使用sync.Map或线程安全的缓存框架,本文就详细的介绍了go缓存库freecache,感兴趣的可以了解一下
    2022-02-02
  • go语言检测文件是否存在的方法

    go语言检测文件是否存在的方法

    这篇文章主要介绍了go语言检测文件是否存在的方法,实例分析了Go语言文件操作的相关技巧,需要的朋友可以参考下
    2015-03-03
  • Go语言中new()和 make()的区别详解

    Go语言中new()和 make()的区别详解

    这篇文章主要介绍了Go语言中new()和 make()的区别详解,本文讲解了new 的主要特性、make 的主要特性,并对它们的区别做了总结,需要的朋友可以参考下
    2014-10-10
  • gorm乐观锁使用小结

    gorm乐观锁使用小结

    本文主要介绍了gorm乐观锁使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-08-08
  • Beego中ORM操作各类数据库连接方式详细示例

    Beego中ORM操作各类数据库连接方式详细示例

    这篇文章主要为大家介绍了Beego中ORM操作各类数据库连接方式详细示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • 细说Go语言中空结构体的奇妙用途

    细说Go语言中空结构体的奇妙用途

    Go语言中,我们可以定义空结构体,即没有任何成员变量的结构体,使用关键字 struct{} 来表示。这种结构体似乎没有任何用处,但实际上它在 Go 语言中的应用非常广泛,本文就来详解讲讲
    2023-05-05

最新评论