2015-12-25 22 views
0

我最近開始學習了。對此唯一的共鳴是似乎只存在於這種語言中的goroutine事物(我擁有java背景,並且說實話,不會完全切換到)。 我想實現一個簡單的端口掃描器,它可以在給定的網絡範圍內找到每個http服務器(打開端口80的主機)。下面是我如何做到這一點:試圖在端口掃描器中執行

package main 

import (
    "net" 
    "fmt" 
    "regexp" 
    "strconv" 
    "time" 
) 

// next two functions are shamelessly copied from somewhere 

func ip2long(ipstr string) (ip uint32) { 
    r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})` 
    reg, err := regexp.Compile(r) 
    if err != nil { 
     return 
    } 
    ips := reg.FindStringSubmatch(ipstr) 
    if ips == nil { 
     return 
    } 
    ip1, _ := strconv.Atoi(ips[1]) 
    ip2, _ := strconv.Atoi(ips[2]) 
    ip3, _ := strconv.Atoi(ips[3]) 
    ip4, _ := strconv.Atoi(ips[4]) 
    if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 { 
     return 
} 
    ip += uint32(ip1 * 0x1000000) 
    ip += uint32(ip2 * 0x10000) 
    ip += uint32(ip3 * 0x100) 
    ip += uint32(ip4) 
    return 
} 
func long2ip(ip uint32) string { 
    return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24) 
} 

// the actual code 
func main() { 
    seconds := 10 // timeout 
    fmt.Println(seconds) // just to see it 
    timeOut := time.Duration(seconds) * time.Second // time out to pass to the DialTimeout 
    can := make(chan int) // a chan 
    req := func (ip string){ // parallelized function to do requests 
    c, err := net.DialTimeout("tcp", ip+":80",timeOut) // connect to ip with given timeout 
    if err == nil { // if we're connected 
     fmt.Println(ip) // output the successful ip 
     c.Close() // close connection 
    } 
    can <- 0 // tell that we're done 

} 

    startIp := ip2long("50.97.99.0") // starting ip 
    endIp := ip2long("50.97.102.0") 
    curIp := startIp // current ip 

    go func(){ // a demon function ran as goroutine which listens to the chan 
     count := 0 // how many ips we processed 
     looper: // label to break 
     for{ 
      <- can // wait for some goroutine to finish 
      curIp++ // next ip 
      count++ 
      go req(long2ip(curIp)) // start new goroutine 
      if (curIp > endIp) { // if we've walked through the range 
       fmt.Println("final") 
       break looper; 
      } 
     } 
    }() 
    numGoes := 100 // number of goroutines ran at one time 
    for i := 0; i < numGoes; i++{ 
     can <- 0 // start 100 goroutines 
    } 
    // standard way to make the program hung 
    var input string 
    fmt.Scanln(&input) 
} 

我希望代碼是很好的評論,所以你可以看到我想要做的。 IP範圍是一些託管公司的範圍,我知道IP 50.97.99.189運行http服務器,但問題是,這個IP永遠不會顯示在控制檯,當我運行我的給定的代碼,雖然主機是up和ping時間大約是156 ms,所以10秒就足夠了。 所以這個問題 - 我做錯了什麼?

回答

0

這是一個稍微修改過的版本,是更習慣去。

有很短的寫法,但這可能更清楚。

邏輯基本相同。我只是運行它,它運行良好,打印出它連接到的幾個ips。該版本還打印出爲什麼會失敗,這更多用於故障排除。

運行此版本時是否仍然存在問題?如果是這樣,你會得到什麼錯誤?

我的版本,on Play

package main 

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

// next two functions are shamelessly copied from somewhere 

func ip2long(ipstr string) (uint32, error) { 
    r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})` 
    reg, err := regexp.Compile(r) 
    if err != nil { 
     return 0, err 
    } 
    ips := reg.FindStringSubmatch(ipstr) 
    if ips == nil { 
     return 0, fmt.Errorf("Invalid ip address") 
    } 
    var ip1, ip2, ip3, ip4 int 
    if ip1, err = strconv.Atoi(ips[1]); err != nil { 
     return 0, err 
    } 
    if ip2, err = strconv.Atoi(ips[2]); err != nil { 
     return 0, err 
    } 
    if ip3, err = strconv.Atoi(ips[3]); err != nil { 
     return 0, err 
    } 
    if ip4, err = strconv.Atoi(ips[4]); err != nil { 
     return 0, err 
    } 
    if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 { 
     return 0, fmt.Errorf("Invalid ip address") 
    } 
    ip := uint32(ip1 * 0x1000000) 
    ip += uint32(ip2 * 0x10000) 
    ip += uint32(ip3 * 0x100) 
    ip += uint32(ip4) 
    return ip, nil 
} 
func long2ip(ip uint32) string { 
    return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24) 
} 

// the actual code 
func main() { 
    timeOut := 10 * time.Second // time out to pass to the DialTimeout 
    fmt.Println("Timeout is:", timeOut) 
    req := func(ip string) { // parallelized function to do requests 
     c, err := net.DialTimeout("tcp", ip+":80", timeOut) // connect to ip with given timeout 
     if err == nil {          // if we're connected 
      fmt.Println(ip) // output the successful ip 
      c.Close()  // close connection 
     } else { 
      fmt.Println("Error is:", err) 
     } 
    } 

    startIp, err := ip2long("50.97.99.0") // starting ip 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    endIp, err := ip2long("50.97.102.0") 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    var wg sync.WaitGroup // synchronizer for main routine to wait for spawned workers 
    ips := make(chan uint32) // channel to feed ip addrs 

    //spawn 100 workers 
    for idx := 0; idx < 100; idx++ { 
     wg.Add(1) 
     go func() { 
      for ip := range ips { 
       req(long2ip(ip)) // perform check of ip 
      } 
      wg.Done() 
     }() 
    } 

    // send ip addrs to workers to process 
    for curIp := startIp; curIp <= endIp; curIp++ { 
     ips <- curIp 
    } 
    close(ips) // signal goroutines to end 
    wg.Wait() //wait for all goroutines to complete 
}