主 goroutine Golang 中无法接收沿通道发送的最后一个值。这是由于当通道被关闭后,goroutine 无法再次接收到新的值。相反,它将一直阻塞在接收操作上,直到通道中的所有值都被接收完毕。这是 Golang 中的一种设计选择,旨在避免在接收操作过程中可能出现的死锁情况。因此,在编写 Golang 程序时,我们需要特别注意这一点,以避免潜在的问题和错误。
给定 golang 中的 TCP 端口扫描器。 2个实现,第一个是我的,第二个来自golang书。假设第二个是 100% 可行的,正如许多读者之前测试的那样。但似乎两者都有相同的问题:在结果通道中发送的最后一个值无法在主协程中接收,它陷入无限等待来自通道的值,尽管该值实际上已发送。 一些观察:当端口数量少于 21 个时,它按预期工作;当金额超过1000时,未收到的金额增加到10左右。 我不明白为什么。
书中的实现
func worker(ports, results chan int) { for p := range ports { address := fmt.Sprintf("scanme.nmap.org:%d", p) conn, err := net.Dial("tcp", address) if err != nil { results <- 0 fmt.Println("sent", p) continue } conn.Close() results <- p fmt.Println("sent", p) } } func main() { ports := make(chan int, 100) results := make(chan int) var openports []int for i := 0; i < cap(ports); i++ { go worker(ports, results) } go func() { for i := 1; i <= 50; i++ { ports <- i } }() for i := 0; i < 50; i++ { port := <-results // after 49 it gets stuck infinitely, never proceed further fmt.Println("received", port, i) if port != 0 { openports = append(openports, port) } } close(ports) close(results) sort.Ints(openports) fmt.Println(openports) }
通过向 net.Dialer 添加超时已解决该问题
func worker(ports, results chan int) { dialer := net.Dialer{Timeout: time.Second} for p := range ports { address := fmt.Sprintf("scanme.nmap.org:%d", p) conn, err := dialer.Dial("tcp", address) if err != nil { results <- 0 continue } conn.Close() results <- p } }
以上是主 goroutine Golang 中无法接收沿通道发送的最后一个值的详细内容。更多信息请关注PHP中文网其他相关文章!