zoukankan      html  css  js  c++  java
  • Golang 写一个端口扫描器

    前话

    最近痴迷于Golang这个新兴语言,因为它是强类型编译型语言,可以直接编译成三大平台的二进制执行文件,可以直接运行无需其他依赖环境。而且Golang独特的goroutine使得多线程任务执行如new一个对象般简单。

    带着为学习理解Golang的好奇心情,我试着写了个端口扫描器。

    github项目链接如下, 更多的实用工具我会慢慢添加。
    https://github.com/pwcong/go-tools

    源码

    package main
    
    import (
    	"flag"
    	"fmt"
    	"net"
    	"os"
    	"regexp"
    	"strconv"
    	"strings"
    	"sync"
    )
    
    var port int
    var portRange string
    
    var parallelCounts int
    
    func init() {
    
    	flag.IntVar(&port, "p", 80, "port")
    	flag.StringVar(&portRange, "r", "", "range ports. format is <from>~<to>. eg. 100~200")
    	flag.IntVar(&parallelCounts, "n", 1, "parallel counts")
    
    	// 修改提示信息
    	flag.Usage = func() {
    		fmt.Fprintf(os.Stderr, "
    Usage: %s [Options] <IP>
    
    Options:
    
    ", os.Args[0])
    		flag.PrintDefaults()
    	}
    
    	flag.Parse()
    
    }
    
    func printOpeningPort(port int) {
    
    	fmt.Println("port " + strconv.Itoa(port) + " is opening")
    
    }
    
    func checkPort(ip net.IP, port int, wg *sync.WaitGroup, parallelChan *chan int) {
    
    	defer wg.Done()
    
    	tcpAddr := net.TCPAddr{
    		IP:   ip,
    		Port: port,
    	}
    
    	conn, err := net.DialTCP("tcp", nil, &tcpAddr)
    
    	if err == nil {
    		printOpeningPort(port)
    		conn.Close()
    
    	}
    
    	<-*parallelChan
    
    }
    
    func main() {
    
    	args := flag.Args()
    
    	if len(args) != 1 {
    		flag.Usage()
    	} else {
    
    		ip := net.ParseIP(flag.Arg(0))
    
    		// 用于协程任务控制
    		wg := sync.WaitGroup{}
    
    		if portRange != "" {
    
    			matched, _ := regexp.Match(`^d+~d+$`, []byte(portRange))
    
    			if !matched {
    
    				flag.Usage()
    
    			} else {
    
    				portSecs := strings.Split(portRange, "~")
    
    				startPort, err1 := strconv.Atoi(portSecs[0])
    				endPort, err2 := strconv.Atoi(portSecs[1])
    
    				if err1 != nil || err2 != nil || startPort < 1 || endPort < 2 || endPort <= startPort || parallelCounts < 1 {
    					flag.Usage()
    				} else {
    
    					wg.Add(endPort - startPort + 1)
    
    					// 用于控制协程数
    					parallelChan := make(chan int, parallelCounts)
    
    					for i := startPort; i <= endPort; i++ {
    
    						parallelChan <- 1
    
    						go checkPort(ip, i, &wg, &parallelChan)
    
    					}
    
    					wg.Wait()
    
    				}
    
    			}
    
    		} else {
    
    			wg.Add(1)
    
    			parallelChan := make(chan int)
    
    			go func() {
    				parallelChan <- 1
    			}()
    
    			go checkPort(ip, port, &wg, &parallelChan)
    
    			wg.Wait()
    
    		}
    
    	}
    
    }
    

    运行结果

    1. 执行 go build ./main.go, 生成二进制文件
    2. 运行二进制文件,结果如下:
      $ port-scanner.exe
      
      Usage: E:Program FilesGoPathinport-scanner.exe [Options] <IP>
      
      Options:
      
        -n int
              parallel counts (default 1)
        -p int
              port (default 80)
        -r string
              range ports. format is <from>~<to>. eg. 100~200
      
      $ port-scanner.exe -p 80 127.0.0.1
      port 80 is opening
      
      $ port-scanner.exe -r 1~100 -n 50 127.0.0.1
      port 80 is opening
      
  • 相关阅读:
    安装pip
    Jmeter查看吞吐量
    maven打包为jar文件时,解决scope为system的jar包无法被打包进jar文件的解决方案。
    spring cloud unavailable-replicas
    IDEA实用插件
    spring-mvc项目整合jetty实现单war包自启动webapp
    集成多数据源支持和REDIS后只有一个配置能起作用的处理。
    spring整合redis缓存,以注解(@Cacheable、@CachePut、@CacheEvict)形式使用
    基于spring的aop实现多数据源动态切换
    安装Oracle11gR2先决条件检查失败的详细解决处理过程
  • 原文地址:https://www.cnblogs.com/pwc1996/p/8059440.html
Copyright © 2011-2022 走看看