在这种情况下如何正确循环缓冲通道?

我正在尝试使用标准库来制作某种端口扫描器。这更像是一个练习,所以请不要评论所涉及的逻辑。


查看以下代码:


package main


import (

    "flag"

    "fmt"

    "net"

    "time"

    "strings"

    "strconv"

    "log"

    "sync"

)


var commonPorts = map[int]string {

    21: "ftp",

    22: "sftp",

    80: "http",

    110: "pop3",

    143: "imap",

    443: "https",

    631: "ipp",

    993: "imaps",

    995: "pop3s",

}


type OP struct {

    mu sync.Mutex

    ports []string

}


func (o *OP) SafeAdd(port string) {

    o.mu.Lock()

    defer o.mu.Unlock()

    o.ports = append(o.ports, port)

}



func worker(host string, port int) string {

    address := fmt.Sprintf("%s:%d", host, port)


    conn, err := net.DialTimeout("tcp", address, time.Second * 3)

    if err != nil {

        return ""; // is offline, cannot connect

    }

    conn.Close()


    stringI := strconv.Itoa(port)

    if name, ok := commonPorts[port]; ok {

        stringI += fmt.Sprintf("(%s)", name)

    }


    return stringI

}

有两种开始扫描的方法,一种是使用缓冲通道,另一种是使用 sync.GroupWait 并在所有扫描完成后退出。


在我看来,在这种情况下,使用 sync.GroupWait 比使用缓冲通道并循环遍历它直到它为空更有意义。然而,在这里使用缓冲通道,我没有看到一种方法来检测通道上没有其他东西,我应该从 for 循环中退出,除非使用另一个 sync.WaitGroup 块。


我想我的问题是,如果我只想使用缓冲通道解决方案,我如何正确实现它,以便我知道处理何时完成,以便我可以继续执行其余代码?(请不要建议超时)。


这也是这两种类型的一个小基准,以防有人感兴趣:


MacBook-Pro:PortScanner c$ time ./PortScanner -host yahoo.com -type 1

Scanning: yahoo.com...

Following ports are opened: 80(http), 143(imap), 110(pop3), 995(pop3s), 993(imaps)


real    0m4.620s

user    0m1.193s

sys     0m1.284s

MacBook-Pro:PortScanner c$ time ./PortScanner -host yahoo.com -type 2

Scanning: yahoo.com...

Following ports are opened: 110(pop3), 80(http), 143(imap), 995(pop3s), 993(imaps)


real    0m4.055s

user    0m1.051s

sys     0m0.946s


人到中年有点甜
浏览 141回答 1
1回答

达令说

processWithChannels如果您需要将超过 1000 个项目放入频道,则调用将挂起。如果您打算使用缓冲通道来保存所有值直到处理,则必须有足够的容量来接受所有值。如果您要将所有值收集到一个切片中,则没有理由使用通道,您的第二个解决方案就很好。如果您想尽快“流”回端口,那么您需要介于两种解决方案之间ports := make(chan string)var wg sync.WaitGroupfor i := 1; i <= 65535; i++ {&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func(i int) {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; if port := worker(*host, i); port != "" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ports <- port&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }(i)}go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(ports)}()for port := range ports {&nbsp; &nbsp; fmt.Println("PORT:", port)}然而,这很可能会遇到问题,例如当您同时拨打所有 65535 端口时丢失开放端口。这是使用一组工作人员同时拨号的一种可能模式:ports := make(chan string)toScan := make(chan int)var wg sync.WaitGroup// make 100 workers for dialingfor i := 0; i < 100; i++ {&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; for p := range toScan {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ports <- worker(*host, p)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()}// close our receiving ports channel once all workers are donego func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(ports)}()// feed the ports to the worker poolgo func() {&nbsp; &nbsp; for i := 1; i <= 65535; i++ {&nbsp; &nbsp; &nbsp; &nbsp; toScan <- i&nbsp; &nbsp; }&nbsp; &nbsp; // signal the workers to stop&nbsp; &nbsp; close(toScan)}()for port := range ports {&nbsp; &nbsp; if port != "" {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("PORT:", port)&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go