I start two goroutines to forward message between two io.ReadWriter
where rw1
is a TCP connection with type Conn.net
and rw2
is the type of *os.File
which use pty
library to build telnet connection. Here comes the forwarding code:
func Connection(northConn net.Conn) {
// code omit ...
transport(northConn, sourthConn)
// code omit ...
sourthConn.Close() // close
}
func transport(rw1, rw2 io.ReadWriter) error {
errc := make(chan error, 1)
go func() {
_, err := io.Copy(rw1, rw2)
errc <- err
}()
go func() {
_, err := io.Copy(rw2, rw1)
errc <- err
}()
err := <-errc
if err != nil && err == io.EOF {
err = nil
}
return err
}
The pipeline is "A
<->rw1(northConn)
<->rw2(sourthConn)
<->telnet server
" where A communicate with rw1 through TCP connection, rw2
communicate with telnet server through *os.File
read and write. The above two goroutines just forwarding message between rw1
and rw2
.
These two goroutines can be normally closed if sending exit
command from A
so that connection between rw2
and telnet server
close firstly and A
<->rw1
close secondly. But if I shutdown the A terminal which means sending EOF
to rw1
only, the A
<->rw1
connection can be closed while rw2
<->telnet server
not. The second goroutine can exit normally while the first goroutine is still blocking at io.Copy(rw1, rw2)
. And the sourthConn.Close()
is blocking too.
So my question is how to make the first goroutine exit in this situation and the sourth.Close()
run unblocking? I came up with an idea that send exit
command in the second goroutine after rw1
receive EOF
but I don't know whether this is a good method and whether this may bring bugs:
go func() {
_, err := io.Copy(rw2, rw1)
rw2.Write([]byte("exit
")) // add this sentence
errc <- err
}()
How can I shutdown the *os.File
directly from outside?