Maison >développement back-end >Golang >Comment lire entièrement le contenu mis en mémoire tampon du socket TCP après la fermeture de la connexion client ?

Comment lire entièrement le contenu mis en mémoire tampon du socket TCP après la fermeture de la connexion client ?

PHPz
PHPzavant
2024-02-11 16:33:18483parcourir

关闭客户端连接后如何从 tcp 套接字完全读取缓冲内容?

En programmation réseau, comment lire complètement le contenu mis en mémoire tampon du socket TCP après la fermeture de la connexion client est un problème courant. Lorsque le client ferme la connexion, il peut encore y avoir des données non lues côté serveur. Afin de garantir une lecture complète du contenu du tampon, les méthodes suivantes peuvent être utilisées : 1. Utiliser la lecture en boucle jusqu'à ce que l'indicateur de fin de données soit lu. 2. Définir un délai d'attente et sortir de la boucle si les données ne sont pas lues dans le délai ; heure spécifiée ; 3. Utilisez un socket non bloquant et vérifiez s'il y a des données à lire par interrogation. La méthode ci-dessus peut garantir que le contenu du tampon est entièrement lu à partir du socket TCP, améliorant ainsi la stabilité et la fiabilité de la communication réseau.

Contenu de la question

J'ai un serveur Go qui écoute sur un socket TCP, et pendant l'arrêt, je veux qu'il dise au client d'arrêter d'envoyer plus de données, mais aussi de lire tout ce que le client a envoyé jusqu'à présent. Ce que je vois, c'est qu'une fois la connexion client fermée, le serveur arrête de lire, mais il ne reçoit jamais tout ce que le client pensait avoir envoyé. Ce que je pense, c'est que le système d'exploitation met en mémoire tampon les paquets TCP reçus, puis les supprime lorsque le serveur ferme la connexion client.

Voici un programme qui montre le problème. Le serveur écoute et imprime ce qu'il reçoit ; le client envoie et imprime ce qu'il envoie. Le serveur interrompt le client pour l'arrêter, mais à la fin je veux que les deux listes soient identiques.

  • Cet exemple utilise bufio.scanner pour lire le socket, mais j'ai également essayé de simplement lire les octets de la connexion mais j'ai obtenu le même résultat.

  • conn.(*net.tcpconn).closewrite() Cela ressemble exactement à ce que je veux, mais cela ne semble pas du tout briser le client.

  • conn.(*net.tcpconn).setreadbuffer(0) - J'ai essayé ça aussi, mais 0 n'est pas une valeur autorisée (panique).

package main

import (
    "bufio"
    "fmt"
    "net"
    "strconv"
    "sync"
    "time"
)

const port = ":8888"

var wg sync.waitgroup

func main() {
    wg.add(1)
    go func() {
        // wait for the server to start
        time.sleep(1000 * time.millisecond)
        client()
    }()

    // server listens
    wg.add(1)
    server()

    wg.wait()
}

func server() {
    defer wg.done()

    listener, err := net.listen("tcp", port)
    if err != nil {
        panic(err)
    }

    received := make([]string, 0)
    conn, err := listener.accept()
    if err != nil {
        panic(err)
    }

    defer conn.close()

    scanner := bufio.newscanner(conn)

    for i := 0; scanner.scan(); i++ {
        received = append(received, scanner.text())

        // arbitrary condition: simulate a server shutdown - interrupt the client
        if len(received) == 2 {
            _ = conn.(*net.tcpconn).close()
        }
    }

    fmt.println("server received: ", received)
}

func client() {
    defer wg.done()

    conn, err := net.dial("tcp", port)
    if err != nil {
        panic(err)
    }

    sent := make([]string, 0)
    defer conn.close()

    for i := 0; i < 50000; i++ {
        v := strconv.itoa(i)
        _, err := conn.write([]byte(v + "\n"))
        if err != nil {
            fmt.println("client interrupted:", err)
            break
        } else {
            sent = append(sent, v)
            // slow down the sends to make output readable
            //time.sleep(1 * time.millisecond)
        }
    }
    fmt.println("client sent: ", sent)
}

Le résultat sur ma machine est comme ceci :

Server received:  [0 1 2]
Client interrupted: write tcp 127.0.0.1:49274->127.0.0.1:8888: write: broken pipe
Client sent:  [0 1 2 3 4 5 6 7 8 9 10 11 12 13]

Workaround

TCP fournit uniquement un flux d'octets bidirectionnel fiable sans aucune sémantique inhérente. Si le serveur souhaite que le client signale qu'il ne doit plus envoyer de données, il doit implémenter cette fonctionnalité dans le cadre du protocole d'application, une couche au-dessus du transport de données pur fourni par TCP.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer