. Inilah sebabnya mengapa beberapa algoritma PING/PONG atau TCP keep-alive digunakan. Saya mencipta aplikasi pelayan-pelanggan yang mudah di mana pelanggan menyambung ke pelayan dan menghantar mesej ringkas selepas 10 saat. Apa yang mengelirukan saya ialah bagaimana pelayan mengetahui bahawa pelanggan tidak lagi wujud dalam dua kes berikut:
Saya membiarkan program berjalan sepenuhnya dan lengkap - dalam kes ini pelayan menutup sambungan (saya tidak faham bagaimana pelayan mengetahui bahawa klien tiada lagi, saya tidak menunjukkan mana-mana pada klien bahawa saya sedang menutup sambungan)
Error Reading: read tcp 127.0.0.1:8080->127.0.0.1:60845 : wsarecv: 现有连接被远程主机强行关闭.
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.gonet
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) } }
Saya sedar saya bercakap tentang sesuatu yang saya tidak begitu biasa, jadi saya mengujinya sendiri. Contoh mainan, dalam tiga terminal berasingan pada mesin yang sama:
Penyeliaan:Pelanggan:
sudo tcpdump -tttt -i lo port 8887
(您可能需要找出您的本地主机设备是什么,也许是 lo0
,使用 sudo tcpdump -D
。观察 Flags 字段:.
Pelanggan: SYNnc -l 8887
nc localhost 8887
Pelanggan: ACK
Taip pelayan dan tekan Enter
a) Hentikan pelanggan, sama ada melalui ctrl-c atau sigkill:
Pelanggan: ACK
Kemudian hentikan pelanggan:
Percubaan ini telah diselesaikan pada WSL/Ubuntu. Saya belum menyusun atur cara anda lagi, tetapi anda boleh menguji sendiri senario anda. Satu perkara yang mengejutkan saya ialah walaupun saya menghentikan proses klien, FIN masih dihantar, menunjukkan bahawa jika proses klien ditamatkan dengan port terbuka, adalah tanggungjawab kernel untuk menghantar FIN. Selain itu, apabila proses bahagian pelayan dihentikan, FIN tidak dihantar, menyebabkan klien menghadapi respons RST.
Atas ialah kandungan terperinci Bagaimanakah pelayan mengetahui bahawa klien tidak lagi wujud?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!