卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章35377本站已运行395

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

关闭客户端连接后如何从 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 提供的纯数据传输之上的一层。

卓越飞翔博客
上一篇: 如何使用 TOML 装置在使用 Go Buffalo 框架的开发环境中为我的数据库播种?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏