>  기사  >  백엔드 개발  >  서버는 클라이언트가 더 이상 존재하지 않는다는 것을 어떻게 알 수 있습니까?

서버는 클라이언트가 더 이상 존재하지 않는다는 것을 어떻게 알 수 있습니까?

PHPz
PHPz앞으로
2024-02-08 20:50:03413검색

서버는 클라이언트가 더 이상 존재하지 않는다는 것을 어떻게 알 수 있습니까?

질문 내용

저는 TCP가 어떻게 작동하는지 이해하려고 노력하고 있으며 지금까지 제가 아는 것은 "무작위" 연결 끊김이 발생하면 한쪽이 다른 쪽이 아직 살아 있는지 알 수 없다는 것뿐입니다. 이것이 일부 PING/PONG 알고리즘이나 TCP 연결 유지가 사용되는 이유입니다. 클라이언트가 서버에 연결하고 10초 후에 간단한 메시지를 보내는 간단한 클라이언트-서버 애플리케이션을 만들었습니다. 나를 혼란스럽게 하는 것은 다음 두 가지 경우에 클라이언트가 더 이상 존재하지 않는다는 것을 서버가 어떻게 아는가입니다.

  1. 프로그램을 완전히 실행하고 종료합니다. 이 경우 서버는 연결을 닫습니다. (클라이언트가 더 이상 주변에 없다는 것을 서버가 어떻게 아는지 이해할 수 없습니다. 클라이언트 어디에도 연결을 닫고 있다는 것을 표시하지 않았습니다. 연결)
  2. 클라이언트 프로세스가 완료되기 전에(서버에 메시지를 보내기 전에) 닫았습니다. 이 경우 서버는 다음 메시지를 인쇄합니다. Error Reading: read tcp 127.0.0.1:8080->127.0.0.1:60845 : wsarecv: 现有连接被远程主机强行关闭. (다시 말하지만, 클라이언트가 더 이상 존재하지 않는다는 것을 어떻게 아는지 모르겠습니다.)

운영 체제(또는 golang net 라이브러리)가 관련되어 있고 TCP 연결이 실제로 닫히기 전에 추가 메시지나 유사한 메시지를 보내 이 상황을 처리한다고 가정합니다.

어떤 도움이라도 환영합니다. 다음은 로컬 또는 온라인 Go Playground에서 실행할 수 있도록 제가 사용한 전체 코드입니다.

client.go

으아악

server.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])
}

정답


제가 잘 모르는 내용을 얘기하고 있다는 걸 깨닫고 직접 테스트해봤습니다. 동일한 기계에 있는 세 개의 별도 터미널에 있는 장난감 예:

감독: sudo tcpdump -tttt -i lo port 8887(您可能需要找出您的本地主机设备是什么,也许是 lo0,使用 sudo tcpdump -D。观察 Flags 字段:. ACK이고 나머지는 설명이 필요합니다. )

서버:nc -l 8887

클라이언트:nc localhost 8887

  • 클라이언트: SYN
  • 서버: SYN ACK
  • 클라이언트: ACK

클라이언트를 입력하고 Enter를 누르세요

  • 클라이언트: PSH ACK
  • 서버: ACK

서버를 입력하고 Enter를 누르세요

  • 서버: PSH ACK
  • 클라이언트: ACK

a) ctrl-c 또는 sigkill을 통해 클라이언트를 중지합니다.

  • 클라이언트: FIN ACK
  • 서버: FIN ACK
  • 클라이언트: ACK

b) 서버 중지:

  • 서버: FIN ACK
  • 클라이언트: ACK

그런 다음 클라이언트를 중지합니다.

  • 클라이언트: FIN ACK
  • 서버: RST

이 실험은 WSL/Ubuntu에서 완료되었습니다. 아직 프로그램을 컴파일하지 않았지만 시나리오를 직접 테스트할 수 있습니다. 나를 놀라게 한 한 가지는 클라이언트 프로세스를 서명했음에도 불구하고 FIN이 여전히 전송된다는 것입니다. 이는 클라이언트 프로세스가 열린 포트로 종료되면 FIN을 보내는 것이 커널의 책임임을 나타냅니다. 또한 서버 측 프로세스가 중지되면 FIN이 전송되지 않아 클라이언트에서 RST 응답을 받게 됩니다.

TCP 프로토콜의 커널 구현이 이를 처리합니다. conn.Close()에서 일어나는 일과는 별개로 이는 Go와 전혀 관련이 없습니다.

위 내용은 서버는 클라이언트가 더 이상 존재하지 않는다는 것을 어떻게 알 수 있습니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 stackoverflow.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제