ホームページ  >  記事  >  バックエンド開発  >  クライアント接続を閉じた後にバッファリングされたコンテンツを TCP ソケットから完全に読み取るにはどうすればよいですか?

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

PHPz
PHPz転載
2024-02-11 16:33:18472ブラウズ

关闭客户端连接后如何从 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 までご連絡ください。