The options are to close the connection or set the read deadline to a time in the past. Either way, read on the connection will return an error.
The simplest approach for handling these errors is to handle all errors returned from read on the network connection uniformly: close the connection, clean up the resources associated with the connection and move on. It's OK to close the connection twice.
func recv(c net.Conn, msg chan string) {
defer close(msg) // Notify main goroutine that recv is done.
defer c.Close() // Release resources.
input := bufio.NewScanner(c)
// Loop reading lines until read on c returns an error.
// These errors include io.EOF (normal close by the peer),
// the error caused by the main goroutine closing the connection
// and other networking errors.
for input.Scan() {
msg <- input.Text()
}
}
// main
conn, err := s.Accept()
if err != nil {
// handle error
}
msg := make(chan string)
go recv(conn, msg)
for {
select {
case m, ok := <-msg:
if !ok {
// The recv goroutine closed the channel and the connection.
return
}
fmt.Println(m)
case <-timeout:
// Closing the connection causes the recv goroutine to break
// out of the loop. If the recv goroutine received a line of
// text and has yet sent the text to the msg channel, then
// a return from main at this point will cause the recv goroutine
// to block forever. To avoid this, continue looping until until
// the recv goroutine signals that it's done by closing the msg
// channel.
conn.Close()
}
}
}
The application can record that it's shutting down the connection and handle read errors after that point in a special way, but only do that if the application needs to do something special in this situation.