How can I make io.Reader stop reading?

1,823 views
Skip to first unread message

Alexander Menzhinsky

unread,
Nov 16, 2016, 9:51:09 AM11/16/16
to golang-nuts
When implementing a proxy server I would like to stop reading from a connection when another is closed. I use the io.Copy but basically it uses the Read function.
go io.Copy(connOne, connTwo)

Is it possible?

Peter Waller

unread,
Nov 16, 2016, 10:09:40 AM11/16/16
to Alexander Menzhinsky, golang-nuts
If connTwo is closed, Read will return io.EOF, and io.Copy will return. (With no error, because copy runs until io.EOF is reached).

If that's not happening for you, can you give an example to reproduce?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Daniel Theophanes

unread,
Nov 16, 2016, 10:22:25 AM11/16/16
to golang-nuts
You can also use it.CopyContext and cancel the ctx.

Alexander Menzhinsky

unread,
Nov 16, 2016, 11:20:21 AM11/16/16
to golang-nuts, amenz...@gmail.com
func forward(src net.Conn, network, address string, timeout time.Duration) {
 defer src
.Close()


 dst
, err := net.DialTimeout(network, address, timeout)
 
if err != nil {
 log
.Printf("dial err: %s", err)
 
return
 
}


 defer dst
.Close()


 cpErr
:= make(chan error)


 go cp
(cpErr, src, dst)
 go cp
(cpErr, dst, src)


 
select {
 
case err = <-cpErr:
 
if err != nil {
 log
.Printf("copy err: %v", err)
 
}
 
}


 log
.Printf("disconnect: %s", src.RemoteAddr())
}


func cp
(c chan error, w io.Writer, r io.Reader) {
 _
, err := io.Copy(w, r)
 c
<- err


 fmt
.Println("cp end")
}

Seems like it doesn't work, io.Copy() still block its goroutine

On Wednesday, 16 November 2016 18:09:40 UTC+3, Peter Waller wrote:
If connTwo is closed, Read will return io.EOF, and io.Copy will return. (With no error, because copy runs until io.EOF is reached).

If that's not happening for you, can you give an example to reproduce?
On 16 November 2016 at 14:49, Alexander Menzhinsky <amenz...@gmail.com> wrote:
When implementing a proxy server I would like to stop reading from a connection when another is closed. I use the io.Copy but basically it uses the Read function.
go io.Copy(connOne, connTwo)

Is it possible?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Alexander Menzhinsky

unread,
Nov 16, 2016, 11:22:56 AM11/16/16
to golang-nuts
Do you mean io.CopyContext? I wasn't able to find it. 

Peter Waller

unread,
Nov 17, 2016, 5:38:07 AM11/17/16
to Alexander Menzhinsky, golang-nuts
Your original email was ambiguous and said "when a connection is closed", so I gave an answer for when `connTwo` is closed. But your actual question was "when `connOne`" is closed, if I'm understanding correctly given the program you posted. So given the program above, if `dst` is closed you should observe that one goroutine has terminated, correct? Then the question is, "what about that other goroutine"?

The problem is that that other goroutine's Copy is sat in a loop like this:

for {
  read bytes from src (blocked here)
  write bytes to dst
}

`src` in this case has not been closed, so the only way you will notice if `dst` has closed is if you read from `src`, either by closing `src` and returning (via io.EOF) or reading bytes from `src` which then get written to `dst` and cause a "the network connection is broken" style of error, which io.Copy will return.

TL;DR: when the io.Copy(A, B) finishes, call A.Close() and the io.Copy(B, A) will terminate. Calling A.Close() is like forwarding the B.Read()'s io.EOF error.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.

Hoots The Owl

unread,
Nov 17, 2016, 9:53:01 AM11/17/16
to golang-nuts
As far as I understood, Daniel means something like that https://gowalker.org/github.com/northbright/ctx/ctxcopy

среда, 16 ноября 2016 г., 19:22:56 UTC+3 пользователь Alexander Menzhinsky написал:

Peter Waller

unread,
Nov 17, 2016, 9:55:48 AM11/17/16
to Hoots The Owl, golang-nuts
As far as I understand, that seems unlikely to solve the problem of the Read() function being blocked, if that is what is happening here.

--

Alexander Menzhinsky

unread,
Nov 17, 2016, 10:23:06 AM11/17/16
to golang-nuts
I was able to solve the problem with the SetReadDeadline function. 
I check every n second some flag or channel whether to stop reading or not. In case you use net sockets and your reader is closed by other goroutine, the Read function will fail the next for loop iteration with the "reading from closed connection" error. 

for {
err := r.SetReadDeadline(time.Now().Add(5 * time.Second))
if err != nil {
return err
}
_, err = r.Read(buf)
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
// check whether t

continue
}
// ...
}

Munding

unread,
Sep 10, 2022, 6:53:55 PM9/10/22
to golang-nuts
There's only one way(SetReadDeadline to timeout) to stop reading?
Reply all
Reply to author
Forward
0 new messages