TCP连接函数

定义一个connect函数进行TCP连接,接收三个参数:

  • ports chan int:端口管道,用于接收要扫描的端口
  • results chan int:结果管道,用于发送结果
  • host string:主机,用于拼接地址

从端口管道中读取端口后与主机拼接成完整地址,使用net.Dial测试TCP连接是否成功,并将结果发送到results管道,失败则返回0,成功则返回端口。

func connect(ports chan int, results chan int, host string) {
	//  从管道接收要扫描的端口
	for p := range ports {
		//  拼接地址
		address := fmt.Sprintf("%s:%d", host, p)
		//  TCP连接
		conn, err := net.Dial("tcp", address)
		if err != nil {
			results <- 0
			continue
		}
		//  关闭连接
		conn.Close()
		//  将结果发送到管道
		results <- p
	}
}

封装函数

定义一个run函数,接收四个参数:

  • start int:起始端口
  • end int:结束端口
  • rlen int:goroutine池缓存大小
  • host string:主机

该函数用于创建管道和goroutine池,并向管道发送要扫描的端口范围,最后从管道中接收结果,经过排序后返回一个切片。

func run(start int, end int, rlen int, host string) []int {
	//  创建管道
	ports := make(chan int, rlen)
	results := make(chan int)
	//  切片,用于保存扫描的结果
	var openports []int
	//  goroutine池,并发执行TCP连接函数
	for i := 0; i < cap(ports); i++ {
		go connect(ports, results, host)
	}
	//  向管道发送要扫描的端口
	go func() {
		for i := start; i <= end; i++ {
			ports <- i
		}
	}()
	//  从管道接收结果
	for i := start; i <= end; i++ {
		port := <-results
		if port != 0 {
			openports = append(openports, port)
		}
	}
	//  关闭管道
	close(ports)
	close(results)
	//  排序
	sort.Ints(openports)
	//  返回数据
	return openports
}

主函数

调用封装函数,向封装函数传递参数,并输出结果

func main() {
	//  参数
	host := "127.0.0.1"
	start := 0
	end := 66535
	rlen := 4096
	//  调用封装函数,接收返回值
	res := run(start, end, rlen, host)
	//  输出结果
	for _, port := range res {
		fmt.Printf("%d is open\n", port)
	}
}

完整代码

scan.go

package main
 
import (
"fmt"
"net"
"sort"
)
 
func connect(ports chan int, results chan int, host string) {
	//  从管道接收要扫描的端口
	for p := range ports {
		//  拼接地址
		address := fmt.Sprintf("%s:%d", host, p)
		//  TCP连接
		conn, err := net.Dial("tcp", address)
		if err != nil {
			results <- 0
			continue
		}
		//  关闭连接
		conn.Close()
		//  将结果发送到管道
		results <- p
	}
}
 
func run(start int, end int, rlen int, host string) []int {
	//  创建管道
	ports := make(chan int, rlen)
	results := make(chan int)
	//  切片,用于保存扫描的结果
	var openports []int
	//  goroutine池,并发执行TCP连接函数
	for i := 0; i < cap(ports); i++ {
		go connect(ports, results, host)
	}
	//  向管道发送要扫描的端口
	go func() {
		for i := start; i <= end; i++ {
			ports <- i
		}
	}()
	//  从管道接收结果
	for i := start; i <= end; i++ {
		port := <-results
		if port != 0 {
			openports = append(openports, port)
		}
	}
	//  关闭管道
	close(ports)
	close(results)
	//  排序
	sort.Ints(openports)
	//  返回数据
	return openports
}
 
func main() {
	//  参数
	host := "127.0.0.1"
	start := 0
	end := 66535
	rlen := 4096
	//  调用封装函数,接收返回值
	res := run(start, end, rlen, host)
	//  输出结果
	for _, port := range res {
		fmt.Printf("%d is open\n", port)
	}
}