导读:本期聚焦于小伙伴创作的《如何使用Golang实现端口扫描工具检测目标主机端口状态》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何使用Golang实现端口扫描工具检测目标主机端口状态》有用,将其分享出去将是对创作者最好的鼓励。

在网络运维和安全测试工作中,检测目标主机的端口开放状态是排查服务可用性、评估网络风险的基础操作。Golang凭借其原生支持的轻量级协程和高效的网络编程能力,成为实现端口扫描工具的热门选择,能够快速完成大量端口的并发检测,同时代码逻辑清晰易于维护。

端口扫描的核心原理

端口扫描的本质是尝试与目标主机的指定端口建立网络连接,根据连接的结果判断端口状态。常见的端口状态分为三类:

  • 开放:目标端口有服务监听,成功建立连接
  • 关闭:目标端口无服务监听,连接被拒绝
  • 过滤:连接超时或无法到达,可能是防火墙拦截等原因

在Golang中,我们可以通过net.DialTimeout函数尝试建立TCP连接,通过连接返回的错误信息和耗时判断端口状态。

基础版单端口扫描实现

首先实现单个端口的检测逻辑,核心是通过设置合理的超时时间,判断连接是否成功建立:

package main

import (
	"fmt"
	"net"
	"time"
)

// checkPort 检测单个端口状态
// host: 目标主机地址,port: 目标端口号,timeout: 连接超时时间
func checkPort(host string, port int, timeout time.Duration) string {
	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		// 判断错误类型,区分关闭和过滤状态
		if opErr, ok := err.(*net.OpError); ok {
			if opErr.Timeout() {
				return "过滤"
			}
		}
		return "关闭"
	}
	defer conn.Close()
	return "开放"
}

func main() {
	host := "127.0.0.1"
	port := 80
	timeout := 3 * time.Second
	status := checkPort(host, port, timeout)
	fmt.Printf("主机 %s 端口 %d 状态:%sn", host, port, status)
}

并发扫描多个端口

单端口扫描效率较低,实际使用中需要同时扫描多个端口,Golang的goroutine可以很方便地实现并发扫描,同时配合通道收集扫描结果:

package main

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

// PortResult 存储端口扫描结果
type PortResult struct {
	Port   int
	Status string
}

// checkPort 检测单个端口状态
func checkPort(host string, port int, timeout time.Duration, wg *sync.WaitGroup, resultChan chan<PortResult>) {
	defer wg.Done()
	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		if opErr, ok := err.(*net.OpError); ok {
			if opErr.Timeout() {
				resultChan <- PortResult{Port: port, Status: "过滤"}
				return
			}
		}
		resultChan <- PortResult{Port: port, Status: "关闭"}
		return
	}
	defer conn.Close()
	resultChan <- PortResult{Port: port, Status: "开放"}
}

func main() {
	host := "127.0.0.1"
	// 扫描1到100端口
	startPort := 1
	endPort := 100
	timeout := 2 * time.Second

	var wg sync.WaitGroup
	resultChan := make(chan PortResult, endPort-startPort+1)

	// 启动并发扫描
	for port := startPort; port <= endPort; port++ {
		wg.Add(1)
		go checkPort(host, port, timeout, &wg, resultChan)
	}

	// 等待所有扫描完成
	wg.Wait()
	close(resultChan)

	// 输出扫描结果
	fmt.Printf("目标主机 %s 端口扫描结果:n", host)
	openCount := 0
	for res := range resultChan {
		if res.Status == "开放" {
			fmt.Printf("端口 %d:%sn", res.Port, res.Status)
			openCount++
		}
	}
	fmt.Printf("扫描完成,共发现 %d 个开放端口n", openCount)
}

优化扫描体验

上述基础实现还可以做进一步优化,提升工具的实用性和效率:

控制并发数量

无限制启动goroutine可能会导致系统资源占用过高,可以通过有缓冲的通道实现信号量,控制最大并发数:

package main

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

type PortResult struct {
	Port   int
	Status string
}

func checkPort(host string, port int, timeout time.Duration, sem chan struct{}, wg *sync.WaitGroup, resultChan chan<PortResult>) {
	defer wg.Done()
	// 获取信号量,控制并发数
	sem <- struct{}{}
	defer func() { <-sem }()

	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		if opErr, ok := err.(*net.OpError); ok {
			if opErr.Timeout() {
				resultChan <- PortResult{Port: port, Status: "过滤"}
				return
			}
		}
		resultChan <- PortResult{Port: port, Status: "关闭"}
		return
	}
	defer conn.Close()
	resultChan <- PortResult{Port: port, Status: "开放"}
}

func main() {
	host := "127.0.0.1"
	startPort := 1
	endPort := 200
	timeout := 2 * time.Second
	// 最大并发数设置为50
	maxConcurrent := 50
	sem := make(chan struct{}, maxConcurrent)

	var wg sync.WaitGroup
	resultChan := make(chan PortResult, endPort-startPort+1)

	for port := startPort; port <= endPort; port++ {
		wg.Add(1)
		go checkPort(host, port, timeout, sem, &wg, resultChan)
	}

	wg.Wait()
	close(resultChan)

	fmt.Printf("目标主机 %s 端口扫描结果(1-200):n", host)
	for res := range resultChan {
		fmt.Printf("端口 %d:%sn", res.Port, res.Status)
	}
}

支持命令行参数

可以通过flag包让工具支持自定义目标主机、端口范围、超时时间等参数,提升工具的灵活性:

package main

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

type PortResult struct {
	Port   int
	Status string
}

func checkPort(host string, port int, timeout time.Duration, sem chan struct{}, wg *sync.WaitGroup, resultChan chan<PortResult>) {
	defer wg.Done()
	sem <- struct{}{}
	defer func() { <-sem }()

	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		if opErr, ok := err.(*net.OpError); ok {
			if opErr.Timeout() {
				resultChan <- PortResult{Port: port, Status: "过滤"}
				return
			}
		}
		resultChan <- PortResult{Port: port, Status: "关闭"}
		return
	}
	defer conn.Close()
	resultChan <- PortResult{Port: port, Status: "开放"}
}

func main() {
	// 定义命令行参数
	host := flag.String("host", "127.0.0.1", "目标主机地址")
	startPort := flag.Int("start", 1, "起始端口")
	endPort := flag.Int("end", 100, "结束端口")
	timeout := flag.Int("timeout", 2, "超时时间(秒)")
	maxConcurrent := flag.Int("concurrent", 50, "最大并发数")
	flag.Parse()

	connTimeout := time.Duration(*timeout) * time.Second
	sem := make(chan struct{}, *maxConcurrent)

	var wg sync.WaitGroup
	resultChan := make(chan PortResult, *endPort-*startPort+1)

	fmt.Printf("开始扫描主机 %s 的 %d-%d 端口...n", *host, *startPort, *endPort)
	for port := *startPort; port <= *endPort; port++ {
		wg.Add(1)
		go checkPort(*host, port, connTimeout, sem, &wg, resultChan)
	}

	wg.Wait()
	close(resultChan)

	openPorts := make([]int, 0)
	filteredPorts := make([]int, 0)
	closedPorts := make([]int, 0)
	for res := range resultChan {
		switch res.Status {
		case "开放":
			openPorts = append(openPorts, res.Port)
		case "过滤":
			filteredPorts = append(filteredPorts, res.Port)
		case "关闭":
			closedPorts = append(closedPorts, res.Port)
		}
	}

	fmt.Println("n扫描结果统计:")
	fmt.Printf("开放端口:%vn", openPorts)
	fmt.Printf("过滤端口数量:%dn", len(filteredPorts))
	fmt.Printf("关闭端口数量:%dn", len(closedPorts))
}

注意事项

使用端口扫描工具时需要注意以下几点:

  • 未经授权对目标主机进行端口扫描可能违反法律法规,仅可在自己拥有权限的主机或授权的测试环境中使用
  • 超时时间设置需要合理,过短可能导致误判开放端口为过滤状态,过长会降低扫描效率
  • 部分网络环境会对高频端口扫描行为进行拦截,可根据实际情况调整并发数量和扫描间隔
端口扫描工具仅用于合法的网络检测场景,请勿用于非法用途。

Golang端口扫描目标主机端口状态检测修改时间:2026-06-25 21:54:53

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。