Mon serveur senario est comme ceci: Un thread io est en train de lire sur une connexion TCP tout le temps. Après un certain temps, le thread de contrôle peut décider de le fermer en raison d'une faible activité ou pour une autre raison. Si c.Close () est appelé, le thread io rapportera une erreur comme celle-ci: read tcp xxx-> xxx: utilisation d'une connexion réseau fermée .
Le code est comme ceci: p >
func recv(c net.Conn) {
input := bufio.NewScanner(c)
for input.Scan() {
msg <- input.Text()
...
}
}
//main
conn, err := s.Accept()
...
go recv(conn)
for {
select {
case m := <-msg:
...
case <-timeout:
conn.Close() // oops!
}
}
Je pourrais peut-être ignorer l'erreur, mais je me demande s'il existe un meilleur moyen.
3 Réponses :
Les options sont de fermer la connexion ou de a fixé la date limite de lecture à une heure dans le passé. Dans tous les cas, read sur la connexion renverra une erreur.
L'approche la plus simple pour gérer ces erreurs est de gérer uniformément toutes les erreurs renvoyées par la lecture sur la connexion réseau: fermez la connexion, nettoyez les ressources associées à la connexion et continuez. Vous pouvez fermer la connexion deux fois.
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()
}
}
}
L'application peut enregistrer qu'elle ferme la connexion et gérer les erreurs de lecture après ce point dans un manière spéciale, mais ne le faites que si l'application a besoin de faire quelque chose de spécial dans cette situation.
Il y a des erreurs qui suggèrent de gérer seul comme:
EOF: un long message reçu a fini de lire, tout est normal, alors continuez.
"Une connexion existante a été fermée de force par le hôte distant ": le client ferme l'application. C'est normal et la conversation est terminée, alors revenez.
autre: une erreur de connexion ou de serveur, doit être journalisée et corrigée
handler(c net.Conn){
defer c.Close()
for {
...
if e!=nil {
if e == io.EOF{
continue
}
if strings.Contains(e.Error(), "An existing connection was forcibly closed by the remote host.") {
return
}
log.Println(e.Error())
return
}
}
}
Dans votre cas, vous ne voulez pas gérer l'erreur contenant `` utilisation d'une connexion réseau fermée '' .Il est correct de l'ignorer et de ne pas oublier de fermer la boucle.Sinon, de la mémoire va fuir et une routine est suspendue. être une erreur cachée que vous ignorez en répétant encore et encore.
Étant donné que les connexions réseau renvoient io.EOF lorsque l'homologue ferme la connexion, les applications doivent interrompre les boucles de lecture sur cette erreur. La question utilise bufio.Scanner pour lire la connexion. Notez que Scanner.Err () renvoie nil en cas d'erreur EOF, pas io.EOF.
func recv(c *net.Conn) {
if c == nil {
return
}
input := bufio.NewScanner(*c)
for input.Scan() {
msg <- input.Text()
...
}
}
//main
conn, err := s.Accept()
c := &conn
...
go recv(&c)
for {
select {
case m := <-msg:
...
case <-timeout:
conn.Close()
c = nil
}
}
Not sure if this is the best approach. When you close the conn, you can set it to nil and not read from a nil conn value.
@ThunderCat corrigé