Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimanakah pelayan mengetahui bahawa klien tidak lagi wujud?

Bagaimanakah pelayan mengetahui bahawa klien tidak lagi wujud?

PHPz
PHPzke hadapan
2024-02-08 20:50:03413semak imbas

. 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:

Bagaimanakah pelayan mengetahui bahawa klien tidak lagi wujud?

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)
Saya menutup proses klien sebelum ia selesai (sebelum ia menghantar mesej kepada pelayan) - dalam kes ini pelayan mencetak mesej berikut
(Sekali lagi, saya tidak faham bagaimana ia tahu klien tidak lagi wujud)

    Saya mengandaikan sistem pengendalian (atau perpustakaan golang
  1. ) terlibat dan ia mengendalikan situasi ini dengan menghantar mesej tambahan atau serupa sebelum sambungan TCP sebenarnya ditutup.
  2. Sebarang bantuan dialu-alukan. Di bawah ialah kod penuh yang saya gunakan supaya anda boleh menjalankannya secara tempatan atau dalam Go Playground dalam talian. Error Reading: read tcp 127.0.0.1:8080->127.0.0.1:60845 : wsarecv: 现有连接被远程主机强行关闭.
  3. 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.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)
    }
}

Jawapan yang betul

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:
Ia adalah ACK, selebihnya harus jelas. )

Pelayan:

Pelanggan:

sudo tcpdump -tttt -i lo port 8887(您可能需要找出您的本地主机设备是什么,也许是 lo0,使用 sudo tcpdump -D。观察 Flags 字段:.

Pelanggan: SYNnc -l 8887

Pelayan: SYN ACK

nc localhost 8887Pelanggan: ACK

  • Taip klien dan tekan Enter
  • Pelanggan: PSH ACK
  • Pelayan: ACK

Taip pelayan dan tekan Enter
  • Pelayan: PSH ACK
  • Pelanggan: ACK

a) Hentikan pelanggan, sama ada melalui ctrl-c atau sigkill:
  • Pelanggan: FIN ACK
  • Pelayan: FIN ACK

Pelanggan: ACK

  • b) Hentikan pelayan:
  • Pelayan: FIN ACK
  • Pelanggan: ACK

Kemudian hentikan pelanggan:
  • Pelanggan: FIN ACK
  • Pelayan: RST

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.
    Pelaksanaan kernel protokol
  • TCP mengurus perkara ini selain daripada apa yang berlaku dalam
  • ini sama sekali tidak berkaitan dengan Go.

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!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam