Heim >Backend-Entwicklung >Golang >Woher weiß der Server, dass der Client nicht mehr existiert?
Ich versuche zu verstehen, wie TCP funktioniert, und alles, was ich bisher weiß, ist, dass bei einer „zufälligen“ Verbindungsunterbrechung eine Seite keine Möglichkeit hat zu wissen, ob die andere Seite noch am Leben ist. Aus diesem Grund werden einige PING/PONG-Algorithmen oder TCP-Keep-Alive verwendet. Ich habe eine einfache Client-Server-Anwendung erstellt, bei der der Client eine Verbindung zum Server herstellt und nach 10 Sekunden eine einfache Nachricht sendet. Was mich verwirrt, ist, wie der Server in den folgenden beiden Fällen weiß, dass der Client nicht mehr existiert:
Error Reading: read tcp 127.0.0.1:8080->127.0.0.1:60845 : wsarecv: 现有连接被远程主机强行关闭.
(Auch hier verstehe ich nicht, woher er weiß, dass der Client nicht mehr existiert) Ich gehe davon aus, dass das Betriebssystem (oder die Golang net
-Bibliothek) beteiligt ist und diese Situation durch das Senden einer zusätzlichen Nachricht oder ähnliches bewältigt, bevor die TCP-Verbindung tatsächlich geschlossen wird.
Jede Hilfe willkommen. Unten finden Sie den vollständigen Code, den ich verwendet habe, damit Sie ihn lokal oder im Online-Go Playground ausführen können.
client.go
package main import ( "fmt" "net" "time" ) func main() { // Connect to the server conn, err := net.Dial("tcp", "localhost:8080") if err != nil { fmt.Println("Error connecting:", err) return } defer conn.Close() // Send a message to the server message := "Hello from client!" time.Sleep(10000 * time.Millisecond) conn.Write([]byte(message)) // Read the response from the server buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err != nil { fmt.Println("Error reading:", err) return } // Print the server's response fmt.Printf("Received response from server: %s\n", buffer[:n]) }
server.go
package main import ( "fmt" "net" ) func handleConnection(conn net.Conn) { defer conn.Close() // Obtain and print the client's IP address when the connection is established clientAddr := conn.RemoteAddr() fmt.Printf("Client connected from IP address: %s\n", clientAddr) for { // Read data from the client buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err != nil { fmt.Println("Error reading:", err) return } // Print received message fmt.Printf("Received message from client (%s): %s\n", clientAddr, buffer[:n]) // Send a response back to the client response := "Hello from server!" conn.Write([]byte(response)) } } func main() { // Start listening on a port listener, err := net.Listen("tcp", "127.0.0.1:8080") if err != nil { fmt.Println("Error listening:", err) return } defer listener.Close() fmt.Println("Server listening on port 8080") for { // Wait for a connection conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting connection:", err) continue } // Handle the connection in a goroutine go handleConnection(conn) } }
Mir wurde klar, dass ich über etwas sprach, mit dem ich nicht sehr vertraut bin, also habe ich es selbst getestet. Spielzeugbeispiel, in drei separaten Terminals auf derselben Maschine:
Supervision: sudo tcpdump -tttt -i lo port 8887
(您可能需要找出您的本地主机设备是什么,也许是 lo0
,使用 sudo tcpdump -D
。观察 Flags 字段:.
Es ist ACK, der Rest sollte selbsterklärend sein. )
Server:nc -l 8887
Kunde:nc localhost 8887
Geben Sie den Client ein und drücken Sie die Eingabetaste
Geben Sie den Server ein und drücken Sie die Eingabetaste
a) Stoppen Sie den Client, entweder über Strg-C oder Sigkill:
b) Stoppen Sie den Server:
Dann stoppen Sie den Client:
Dieses Experiment wurde auf WSL/Ubuntu abgeschlossen. Ich habe Ihr Programm noch nicht kompiliert, aber Sie können Ihr Szenario selbst testen. Eine Sache, die mich überrascht hat, ist, dass die FIN immer noch gesendet wurde, obwohl ich den Client-Prozess mit einem Signkill beendet habe. Dies zeigt an, dass es in der Verantwortung des Kernels liegt, die FIN zu senden, wenn der Client-Prozess mit einem offenen Port endet. Darüber hinaus wird die FIN nicht gesendet, wenn der serverseitige Prozess gestoppt wird, was dazu führt, dass der Client eine RST-Antwort erhält.
Dafür sorgt die Kernel-Implementierung desTCP-Protokolls; abgesehen davon, was in conn.Close()
passiert, ist das für Go völlig irrelevant.
Das obige ist der detaillierte Inhalt vonWoher weiß der Server, dass der Client nicht mehr existiert?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!