我正在使用两个并发的goroutine将stdin / stdout从我的终端复制到net.Conn目标。由于某种原因,我无法在没有出现紧急错误的情况下(试图关闭关闭的连接)完全停止两个go例程。这是我的代码:
func interact(c net.Conn, sessionMap map[int]net.Conn) {
quit := make(chan bool) //the channel to quit
copy := func(r io.ReadCloser, w io.WriteCloser) {
defer func() {
r.Close()
w.Close()
close(quit) //this is how i'm trying to close it
}()
_, err := io.Copy(w, r)
if err != nil {
//
}
}
go func() {
for {
select {
case <-quit:
return
default:
copy(c, os.Stdout)
}
}
}()
go func() {
for {
select {
case <-quit:
return
default:
copy(os.Stdin, c)
}
}
}()
}
此错误为panic: close of closed channel
我想终止两个go例程,然后通常继续执行另一个功能。我在做什么错了?
答案 0 :(得分:3)
您不能在一个频道上多次调用close
,没有理由在for循环中调用copy
,因为它只能运行一次,并且您正在复制错误的方向,写入stdin并从stdout读取。
简单地询问如何退出2个goroutine很简单,但这并不是您唯一需要在这里做的事情。由于io.Copy
正在阻止,因此您不需要额外的同步来确定呼叫何时完成。这使您可以大大简化代码,从而使推理变得容易得多。
func interact(c net.Conn) {
go func() {
// You want to close this outside the goroutine if you
// expect to send data back over a half-closed connection
defer c.Close()
// Optionally close stdout here if you need to signal the
// end of the stream in a pipeline.
defer os.Stdout.Close()
_, err := io.Copy(os.Stdout, c)
if err != nil {
//
}
}()
_, err := io.Copy(c, os.Stdin)
if err != nil {
//
}
}
还请注意,您可能无法从stdin中退出io.Copy
,因此不能指望interact
函数会返回。在函数体中手动执行io.Copy
并在每个循环中检查半关闭的连接可能是一个好主意,然后您可以早点休息并确保完全关闭net.Conn
。>
答案 1 :(得分:0)
也可能是这样
func scanReader(quit chan int, r io.Reader) chan string {
line := make(chan string)
go func(quit chan int) {
defer close(line)
scan := bufio.NewScanner(r)
for scan.Scan() {
select {
case <- quit:
return
default:
s := scan.Text()
line <- s
}
}
}(quit)
return line
}
stdIn := scanReader(quit, os.Stdin)
conIn := scanReader(quit, c)
for {
select {
case <-quit:
return
case l <- stdIn:
_, e := fmt.Fprintf(c, l)
if e != nil {
quit <- 1
return
}
case l <- conIn:
fmt.Println(l)
}
}