为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
人到中年有点甜 2021-10-25 16:19:50
我正在尝试使用标准库来制作某种端口扫描器。这更像是一个练习,所以请不要评论所涉及的逻辑。查看以下代码:package mainimport (    "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 1Scanning: yahoo.com...Following ports are opened: 80(http), 143(imap), 110(pop3), 995(pop3s), 993(imaps)real    0m4.620suser    0m1.193ssys     0m1.284sMacBook-Pro:PortScanner c$ time ./PortScanner -host yahoo.com -type 2Scanning: yahoo.com...Following ports are opened: 110(pop3), 80(http), 143(imap), 995(pop3s), 993(imaps)real    0m4.055suser    0m1.051ssys     0m0.946s
查看完整描述

1 回答

?
达令说

TA贡献1821条经验 获得超6个赞

processWithChannels如果您需要将超过 1000 个项目放入频道,则调用将挂起。如果您打算使用缓冲通道来保存所有值直到处理,则必须有足够的容量来接受所有值。


如果您要将所有值收集到一个切片中,则没有理由使用通道,您的第二个解决方案就很好。


如果您想尽快“流”回端口,那么您需要介于两种解决方案之间


ports := make(chan string)


var wg sync.WaitGroup

for i := 1; i <= 65535; i++ {

    wg.Add(1)

    go func(i int) {

        defer wg.Done()

        if port := worker(*host, i); port != "" {

            ports <- port

        }

    }(i)

}


go func() {

    wg.Wait()

    close(ports)

}()


for port := range ports {

    fmt.Println("PORT:", port)

}

然而,这很可能会遇到问题,例如当您同时拨打所有 65535 端口时丢失开放端口。这是使用一组工作人员同时拨号的一种可能模式:


ports := make(chan string)

toScan := make(chan int)

var wg sync.WaitGroup


// make 100 workers for dialing

for i := 0; i < 100; i++ {

    wg.Add(1)

    go func() {

        defer wg.Done()

        for p := range toScan {

            ports <- worker(*host, p)

        }

    }()

}


// close our receiving ports channel once all workers are done

go func() {

    wg.Wait()

    close(ports)

}()


// feed the ports to the worker pool

go func() {

    for i := 1; i <= 65535; i++ {

        toScan <- i

    }

    // signal the workers to stop

    close(toScan)

}()


for port := range ports {

    if port != "" {

        fmt.Println("PORT:", port)

    }

}


查看完整回答
反对 回复 2021-10-25
  • 1 回答
  • 0 关注
  • 140 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信