ホームページ  >  記事  >  バックエンド開発  >  サーバーはクライアントが存在しなくなったことをどのようにして知るのでしょうか?

サーバーはクライアントが存在しなくなったことをどのようにして知るのでしょうか?

PHPz
PHPz転載
2024-02-08 20:50:03413ブラウズ

サーバーはクライアントが存在しなくなったことをどのようにして知るのでしょうか?

質問の内容

TCP がどのように機能するかを理解しようとしていますが、これまでにわかっているのは、「ランダムな」切断が発生した場合、一方の側が相手がまだ存在するかどうかを知る方法はありません。このため、一部の PING/PONG アルゴリズムまたは TCP キープアライブが使用されます。クライアントがサーバーに接続し、10 秒後に簡単なメッセージを送信する、単純なクライアント/サーバー アプリケーションを作成しました。私を混乱させるのは、次の 2 つの場合に、サーバーがクライアントが存在しなくなったことをどのように認識するかです。

    プログラムを完全に実行させて完了しました。この場合、サーバーは接続を閉じます(サーバーがクライアントがいなくなったことをどのようにして認識するのかわかりません。クライアントのどこにも閉じていることを示しませんでした)接続)
  1. クライアント プロセスが終了する前 (サーバーにメッセージを送信する前) に閉じてしまいました - この場合、サーバーは次のメッセージを出力しました
  2. Error Reading: read tcp 127.0.0.1:8080->127.0. 0.1 :60845: wsalecv: 既存の接続はリモート ホストによって強制的に閉じられました。 (繰り返しになりますが、クライアントが存在しなくなったことをどのようにして認識するのか理解できません)
オペレーティング システム (または 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])
}


正解


あまり馴染みのないことについて話していることに気づいたので、自分でテストしてみました。おもちゃの例、同じマシン上の 3 つの別々の端末:

監視:

sudo tcpdump -tttt -i lo port 8887 (ローカルホスト デバイスが何であるかを調べる必要があるかもしれません。おそらく lo0 を使用してください。sudo tcpdump -D. Flags フィールドを確認してください: . は ACK、その他は一目瞭然です。)

サーバー:

nc -l 8887

クライアント:

nc ローカルホスト 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 上で完了しました。プログラムはまだコンパイルしていませんが、シナリオを自分でテストできます。私が驚いたことの 1 つは、クライアント プロセスを sigkill したにもかかわらず FIN が送信されたことです。これは、クライアント プロセスがポートが開いた状態で終了した場合、FIN を送信するのはカーネルの責任であることを示唆しています。さらに、サーバー側のプロセスが停止すると、FIN が送信されないため、クライアントは RST 応答を受け取ることになります。

TCP プロトコルのカーネル実装がこれを処理します;

conn.Close() で何が起こるかは別として、これは Go とはまったく関係ありません。

以上がサーバーはクライアントが存在しなくなったことをどのようにして知るのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はstackoverflow.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。