循环中的GO例程 - 函数调用

时间:2016-10-01 18:08:43

标签: go

问题描述

我想在我的 for loop 上发送每次迭代的并发调用。

当前代码

这个程序主要是尝试在服务器上找到一个有效的目录

package main

import (
    "bufio"
    "fmt"
    "net/http"
    "os"
)

func main() {
    var site string
    if len(os.Args) > 1 {
        site = os.Args[1]
    } else {
        fmt.Println("Need the host. Example > http://www.google.com/")
        fmt.Println("wfuzz http://www.google.com/ wordlist.txt")
        site = "http://www.google.com"
        os.Exit(1)
    }
    f, err := os.Open(os.Args[2])

    if err != nil {
        fmt.Println("error opening file!", err)
    }
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        a := site + scanner.Text()
        get_page(a)
    }
    if err := scanner.Err(); err != nil {
        fmt.Println("error", err)
    }

    var input string
    fmt.Scanln(&input)
    fmt.Println("done")

}

func get_page(site string) string {
    a := "\n"
    res, err := http.Get(site)
    if err != nil {
        fmt.Println("error:", err)
    }
    if res.StatusCode != 404 {
        fmt.Println("Page Found!! +::", site, " ::+", res.StatusCode)
    }
    return a
}

实现目标

我想要实现的主要是发送我的for循环并发调用,这样我会加快进程,并且将成为当前程序的最终目标。

3 个答案:

答案 0 :(得分:1)

您可以使用

  

sync.WaitGroup

唯一的问题是你要进行多少次并发通话。

示例

如果wordlist.txt包含此内容

admin.php 
admin
administrator
administrator

你知道你将进行4次并发呼叫

如果内容是

admin.php
admin/
administrator/
administrator/
administrator/
administrator/

你知道你将进行6次并发呼叫。

以下代码是使用3个字的文件

package main

import (
    "fmt"
    "sync"

      "bufio"
   "net/http"
    "os"
)


func main(){



    var site string
    var wg sync.WaitGroup

    if len(os.Args) > 1 {
        site = os.Args[1]
    } else {
        fmt.Println("Need the host. Example > http://www.google.com/")
        fmt.Println("wfuzz http://www.google.com/ wordlist.txt")
        site = "http://www.google.com"
        os.Exit(1)
    }

    f, err := os.Open(os.Args[2])

    if err != nil {
        fmt.Println("error opening file!", err)
    }

     wg.Add(3) // TODO check the number of words in the file 


     scanner := bufio.NewScanner(f)
     for scanner.Scan() {

        a := site + scanner.Text()
        go get_page(a,&wg)

    }

    if err := scanner.Err(); err != nil {
        fmt.Println("error", err)
    }


   wg.Wait()
   fmt.Println("done")

}



func get_page(site string,wg *sync.WaitGroup)  string{
    a := "\n"

    defer wg.Done()

    res, err := http.Get(site)
    if err != nil {
        fmt.Println("error:", err)
    }

    if res.StatusCode != 404 {
        fmt.Println("Page Found!! +::", site, " ::+", res.StatusCode)
    }
    return a

} 

答案 1 :(得分:1)

使用Go标准库sync.WaitGroup和频道的组合,您可以完成此操作,而无需明确跟踪您希望从中读取的文件中的字数。

修改你的get_page(旁注:这不是惯用的去func名称中的用户下划线 - > https://golang.org/doc/effective_go.html#names)func接受额外的频道和等待组,你可以做类似的事情以下内容:

package main

import (
    "bufio"
    "fmt"
    "net/http"
    "os"
    "sync"
)

func main() {

    //your previous code for getting the command line arguments from os.Args, then...

    //create a WaitGroup
    wg := new(sync.WaitGroup)

    //create a channel that you can write your results too
    resultChan := make(chan string)

    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        //increment the waitgroup
        wg.Add(1)
        a := site + scanner.Text()
        //call the getPage with the http target, with the result chan, and the waitgroup
        go getPage(a, resultChan, wg)
    }

    if err := scanner.Err(); err != nil {
        fmt.Println("error", err)
        //if there is an error, close the result chan so progam can exit (for more robust cancellation of potential currently running go routines, take a look at https://blog.golang.org/pipelines)
        close(resultChan)
    }

    //start another go routine to wait for all concurrent calls to get_page to complete, then close the result channel
    go func() {
        wg.Wait()
        close(resultChan)
    }()

    for result := range resultChan {
        //deal with the result in some way
        fmt.Println(result)
    }

    fmt.Println("done")
}

//side note - it is not idiomatic go to use underscores in func name
func getPage(site string, ch chan<- string, wg *sync.WaitGroup) {
    //decrement waitgroup when operation completes
    defer wg.Done()

    res, err := http.Get(site)
    if err != nil {
        ch <- fmt.Sprintf("error: %s", err)
        return
    }
    if res.StatusCode != 404 {
        ch <- fmt.Sprintf("Page Found!! +:: %s ::+ %d", site, res.StatusCode)
    }
}

答案 2 :(得分:0)

您可以使用go get_page(a)为wordlist上的每个单词启动goroutine,以设置使用工作池的最大并发调用。 (https://gobyexample.com/worker-pools