go 实现简易端口扫描的示例

 更新时间:2021年05月22日 10:42:10   作者:codecodify  
该功能实现原理很简单,就是发送socket连接(IP+端口),如果能连接成功,说明目标主机开放了某端口。当要大量扫描端口时,就需要写并发编程了。

我在代码里定义了两个通道,分别用于生产端口和限制连接数,如果不限制连接数,容易被对方检测到或导致对方服务器不能正常运行。

// 生产端口
var port = make(chan int, 10)

// 限制并发数
var connect = make(chan string, 5)

可以使用net库的Dial函数做为socket客户端,需要注意的是要设置超时时间,因为若主机不存在,或目标端口是关闭的,往往需要花费数秒才返回错误,这样扫描大量端口时效率会极其低下。在go中可以使用net.Dialer结构体设置超时时间,然后在调用Dial方法:

d := net.Dialer{Timeout: time.Second}
dial, err := d.Dial("tcp", target)

只要err不等于nil,表示目标端口是对外开放的。
完整代码如下:

package main

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


var wg sync.WaitGroup

func main() {
  var start, end int
  var address string
  fmt.Printf("请输入目标IP:> ")
  fmt.Scan(&address)
  fmt.Printf("请输入起始端口:> ")
  fmt.Scan(&start)
  fmt.Printf("请输入结束端口:> ")
  fmt.Scan(&end)
  wg.Add(end - start + 1)
  Run(address, start, end)
  wg.Wait()
  fmt.Println("执行完毕")
}


// 生产端口
var port = make(chan int, 10)

// 限制并发数
var connect = make(chan string, 5)

func Run(address string,  start, end int) {

  go func() {
    for i := start; i <= end; i++ {
      port <- i
    }
  }()

  go func() {
    // 消费端口
    for p := range port {
      // 往通道写入目标地址,超过限制并发数会阻塞
      connect <- fmt.Sprintf("%s:%d", address, p)
    }
  }()

  go Connect()


}

func Connect() {
  // 并发请求
  for target := range connect {
    // 设置超时时间
    d := net.Dialer{Timeout: time.Second}
    dial, err := d.Dial("tcp", target)
    if err == nil {
      fmt.Printf("%s 连接成功\n", target)
      dial.Close()
    }else{
      fmt.Printf("%s 连接失败\n", target)
    }
    wg.Done()
  }
}

这里端口生产通道不是必须的,只是为了演示消费生产并发模型,当然这还是最简单的。
在Run函数里我没有关闭这两个通道,按官方的说法是gc会回收不使用的通道,如果要手动关闭,可以定义defer闭包进行close。
我本地运行结果如下:

请输入目标IP:> 127.0.0.1
请输入起始端口:> 8080
请输入结束端口:> 8094
127.0.0.1:8080 连接成功
127.0.0.1:8081 连接成功
127.0.0.1:8082 连接成功
127.0.0.1:8083 连接成功
127.0.0.1:8084 连接成功
127.0.0.1:8085 连接成功
127.0.0.1:8086 连接成功
127.0.0.1:8087 连接成功
127.0.0.1:8088 连接成功
127.0.0.1:8089 连接成功
127.0.0.1:8090 连接成功
127.0.0.1:8091 连接成功
127.0.0.1:8092 连接成功
127.0.0.1:8093 连接失败
127.0.0.1:8094 连接失败
执行完毕

这个版本比较简陋,TCP连接过程也可以简化,后续再写另外一篇文章。因为最近在学rust语言,语法内容比较多,所以后面暂时发布编程相关的文章,提升一下语法熟练度。

以上就是go 实现简易端口扫描的示例的详细内容,更多关于go 实现端口扫描的资料请关注脚本之家其它相关文章!

相关文章

  • GO比较两个对象是否相同实战案例

    GO比较两个对象是否相同实战案例

    我们时常有比较两个值是否相等的需求,下面这篇文章主要给大家介绍了关于GO比较两个对象是否相同的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • Go语言实现IP段范围校验示例

    Go语言实现IP段范围校验示例

    这篇文章主要介绍了Go语言实现IP段范围校验示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • golang移除切片索引位置的元素的两种方法

    golang移除切片索引位置的元素的两种方法

    本文主要介绍了golang移除切片索引位置的元素的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • 在Go中动态替换SQL查询中的日期参数的完整步骤

    在Go中动态替换SQL查询中的日期参数的完整步骤

    在处理数据库查询时,经常需要根据不同的输入条件动态地构造SQL语句,尤其是在涉及日期范围的查询中,能够根据实际需求调整查询的起始和结束日期显得尤为重要,在本文中,我将介绍如何在Go语言中实现动态替换SQL查询中的日期参数,需要的朋友可以参考下
    2024-11-11
  • GO env环境变量配置命令使用

    GO env环境变量配置命令使用

    这篇文章主要为大家介绍了GO env环境变量配置命令使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • golang修改结构体中的切片值方法

    golang修改结构体中的切片值方法

    这篇文章主要介绍了golang修改结构体中的切片值方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 解读go在遍历map过程中删除成员是否安全

    解读go在遍历map过程中删除成员是否安全

    在Go语言中,通过for range遍历map时可以安全地删除当前遍历到的元素,因为遍历过程中的删除操作不会影响遍历的进行,但需要注意,遍历顺序是不确定的,删除元素不会导致程序错误,但可能会影响剩余元素的遍历顺序,在多线程环境下
    2024-09-09
  • Go Gin框架优雅重启和停止实现方法示例

    Go Gin框架优雅重启和停止实现方法示例

    Web应用程序中,有时需要重启或停止服务器,无论是因为更新代码还是进行例行维护,这时需要保证应用程序的可用性和数据的一致性,就需要优雅地关闭和重启应用程序,即不丢失正在处理的请求和不拒绝新的请求,本文将详解如何在Go语言中使用Gin这个框架实现优雅的重启停止
    2024-01-01
  • 解析Go的Waitgroup和锁的问题

    解析Go的Waitgroup和锁的问题

    大家在学习go语言的时候,都知道go语言支持并发,使用 goroutine,使用关键字 go 即可,接下来通过本文给大家分享Go的Waitgroup和锁的问题,需要的朋友可以参考下
    2021-05-05
  • 详解Go如何基于现有的context创建新的context

    详解Go如何基于现有的context创建新的context

    在 Golang 中,context 包提供了创建和管理上下文的功能,那么在GO语言中如何基于现有的context创建新的context,下面小编就来和大家详细聊聊
    2024-01-01

最新评论