11

So I'm making a server for my elevator in Go, and I'm running the function "handler" as a goroutine with a TCP-connection. I want it to read from a connection, and if no signal is detected within a certain timespan I want it to return an error.

func handler(conn net.Conn){
    conn.SetReadTimeout(5e9)
    for{
        data := make([]byte, 512)
        _,err := conn.Read(data)
    }
}

As long as I have a client sending stuff over the connection it seems to be working fine, but as soon as the client stops sending the net.Read function returns the error EOF and starts looping with no delay whatsoever.

This might be how Read is supposed to work, but could someone suggest another way to handle the problem without having to close and open the connection every time I want to read something?

1
  • 2
    conn.SetReadTimeout(5e9) is not what you want. SetReadTimeout expects an absolute time, not a duration. Try specifying as "time.Seconds * 10" and the compiler will complain. What you're saying above is that you want the connection to time out at 5000 seconds after Jan 1 1970. So it won't wait at all. Instead you want something to the effect of conn.SetReadTimeout(time.Now().Add(time.Seconds * 10)) for a ten second timeout. Commented Feb 25, 2013 at 21:02

2 Answers 2

22

Read is working as expected I think. It sounds like you want the net.Read to work like a channel in Go. This is pretty easy in go just wrap the net.Read in a running goroutine and use select to read from channels a goroutine is really cheap and so is a channel

Example:

ch := make(chan []byte)
eCh := make(chan error)

// Start a goroutine to read from our net connection
go func(ch chan []byte, eCh chan error) {
  for {
    // try to read the data
    data := make([]byte, 512)
    _,err := conn.Read(data)
    if err != nil {
      // send an error if it's encountered
      eCh<- err
      return
    }
    // send data if we read some.
    ch<- data
  }
}(ch, eCh)

ticker := time.Tick(time.Second)
// continuously read from the connection
for {
  select {
     // This case means we recieved data on the connection
     case data := <-ch:
       // Do something with the data
     // This case means we got an error and the goroutine has finished
     case err := <-eCh:
       // handle our error then exit for loop
       break;
     // This will timeout on the read.
     case <-ticker:
       // do nothing? this is just so we can time out if we need to.
       // you probably don't even need to have this here unless you want
       // do something specifically on the timeout.
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

The documentation explicitly warns against using time.Tick this way.
Also, I'd say a value much smaller than a second would be more appropriate.
1

It is possible that the garbage collector (GC) closes one end of the connection because the net.Conn becomes an unreachable object from GC viewpoint. In order to prevent this: after the client stops sending, make sure that the client connection is stored in a variable that is accessible by your code.

Another option is that somewhere in your program you are closing one end of the connection without knowing about it.

1 Comment

I downvoted thinking you were wrong, but I think you may be right. SO isn't letting me undownvote ATM.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.