クライアント接続を閉じた後にバッファリングされたコンテンツを TCP ソケットから完全に読み取るにはどうすればよいですか?

PHPz
リリース: 2024-02-11 16:33:18
転載
441 人が閲覧しました

关闭客户端连接后如何从 tcp 套接字完全读取缓冲内容?

php エディタ Xiaoxin ネットワーク プログラミングでは、クライアント接続を閉じた後にバッファリングされたコンテンツを TCP ソケットから完全に読み取る方法が一般的な問題になります。クライアントが接続を閉じると、サーバー側に未読のデータが残っている可能性があります。バッファの内容を確実に完全に読み取るには、次の方法を使用できます: 1. データ終了フラグが読み取られるまでループ読み取りを使用します。 2. タイムアウトを設定し、データが時間内に読み取れない場合はループから抜け出します。指定された時間; 3. ノンブロッキングソケットを使用し、ポーリングによって読み取るデータがあるかどうかを確認します。上記の方法により、バッファの内容が TCP ソケットから完全に読み取られることが保証され、ネットワーク通信の安定性と信頼性が向上します。

質問の内容

TCP ソケットでリッスンしている go サーバーがあり、シャットダウン中にクライアントにこれ以上のデータの送信を停止するように指示したいのですが、クライアントのこれまでの内容も読み取りたいと考えています。すべてが送信されました。私が見たのは、クライアント接続が閉じられると、サーバーは読み取りを停止しますが、クライアントが送信したと思ったすべてを受信することはありません。起こっていることは、OS が受信した tcp パケットをバッファリングし、サーバーがクライアント接続を閉じるときにパケットを破棄していることだと思います。

これが問題を表示するプログラムです。サーバーは受信したものをリッスンして出力し、クライアントは送信したものを送信して出力します。サーバーはクライアントを停止するために中断しますが、最終的には両方のリストが同じになるようにします。

  • この例では、bufio.scanner を使用してソケットを読み取りますが、接続からバイトを読み取るだけでも試してみましたが、同じ結果が得られました。

  • conn.(*net.tcpconn).closewrite() これはまさに私が望んでいることのように聞こえますが、これはクライアントをまったく破壊しないようです。

  • conn.(*net.tcpconn).setreadbuffer(0) - これも試しましたが、0 は許可された値ではありません (パニック)。

リーリー

私のマシンの出力は次のようになります:

package main

import (
    "bufio"
    "fmt"
    "net"
    "strconv"
    "sync"
    "time"
)

const port = ":8888"

var wg sync.waitgroup

func main() {
    wg.add(1)
    go func() {
        // wait for the server to start
        time.sleep(1000 * time.millisecond)
        client()
    }()

    // server listens
    wg.add(1)
    server()

    wg.wait()
}

func server() {
    defer wg.done()

    listener, err := net.listen("tcp", port)
    if err != nil {
        panic(err)
    }

    received := make([]string, 0)
    conn, err := listener.accept()
    if err != nil {
        panic(err)
    }

    defer conn.close()

    scanner := bufio.newscanner(conn)

    for i := 0; scanner.scan(); i++ {
        received = append(received, scanner.text())

        // arbitrary condition: simulate a server shutdown - interrupt the client
        if len(received) == 2 {
            _ = conn.(*net.tcpconn).close()
        }
    }

    fmt.println("server received: ", received)
}

func client() {
    defer wg.done()

    conn, err := net.dial("tcp", port)
    if err != nil {
        panic(err)
    }

    sent := make([]string, 0)
    defer conn.close()

    for i := 0; i < 50000; i++ {
        v := strconv.itoa(i)
        _, err := conn.write([]byte(v + "\n"))
        if err != nil {
            fmt.println("client interrupted:", err)
            break
        } else {
            sent = append(sent, v)
            // slow down the sends to make output readable
            //time.sleep(1 * time.millisecond)
        }
    }
    fmt.println("client sent: ", sent)
}
ログイン後にコピー

Solution

TCP は、固有のセマンティクスを持たずに、信頼性の高い双方向バイト ストリームのみを提供します。サーバーがクライアントにデータを送信しないことを通知したい場合は、TCP によって提供される純粋なデータ トランスポートの上の層であるアプリケーション プロトコルの一部としてこの機能を実装する必要があります。

以上がクライアント接続を閉じた後にバッファリングされたコンテンツを TCP ソケットから完全に読み取るにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:stackoverflow.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!