首頁  >  文章  >  後端開發  >  關閉客戶端連線後如何從 tcp 套接字完全讀取緩衝內容?

關閉客戶端連線後如何從 tcp 套接字完全讀取緩衝內容?

PHPz
PHPz轉載
2024-02-11 16:33:18423瀏覽

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

php小編小新在網路程式設計中,關閉客戶端連線後,如何從tcp套接字完全讀取緩衝內容是一個常見問題。當客戶端關閉連線時,伺服器端可能仍然存在未讀取的資料。為了確保完整讀取緩衝內容,可以採用以下幾種方法:1.使用循環讀取,直到讀取到資料結束標誌;2.設定逾時時間,如果在規定時間內未讀取到資料則跳出循環; 3.使用非阻塞套接字,透過輪詢檢查是否有資料可讀。以上方法可確保從tcp套接字完全讀取緩衝內容,提升網路通訊的穩定性與可靠性。

問題內容

我有一個go 伺服器正在偵聽tcp 套接字,在關閉期間我希望它告訴客戶端停止發送更多數據,但也讀取客戶端迄今為止發送的所有內容。我看到的是,一旦客戶端連線關閉,伺服器就會停止讀取,但它永遠不會收到客戶端認為它發送的所有內容。我認為發生的情況是作業系統正在緩衝收到的 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)
}

在我的機器上輸出是這樣的:

Server received:  [0 1 2]
Client interrupted: write tcp 127.0.0.1:49274->127.0.0.1:8888: write: broken pipe
Client sent:  [0 1 2 3 4 5 6 7 8 9 10 11 12 13]

解決方法

TCP僅提供可靠的雙向位元組流,沒有任何固有語意。如果伺服器希望客戶端發出訊號表明它不應再發送任何數據,則必須將此功能實作為應用程式協定的一部分,即 TCP 提供的純資料傳輸之上的一層。

以上是關閉客戶端連線後如何從 tcp 套接字完全讀取緩衝內容?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除