一尘不染

Golang:TCP客户端/服务器数据定界符

go

不确定如何提出问题以及它是否仅与go语言有关,但我想做的是让tcp服务器和客户端之间进行数据交换,基本上,客户端会将大量数据流化为较小的数据如果将数据块发送给服务器,则服务器将等待读取每个数据块,然后回复状态码,客户端将读取该状态码,并基于此状态码执行其他工作。

我使用下面的功能作为 测试 从客户端和服务器读取数据的方法(请注意,我知道这并不完美,但这只是测试):

func createBufferFromConn(conn net.Conn) *bytes.Buffer {
    buffer := &bytes.Buffer{}
    doBreak := false
    for {
        incoming := make([]byte, BUFFER_SIZE)

        conn.SetReadDeadline(time.Now().Add(time.Second * 2))
        bytesRead, err := conn.Read(incoming)
        conn.SetReadDeadline(time.Time{})

        if err != nil {
            if err == io.EOF {
                fmt.Println(err)
            } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
                fmt.Println(err)
            }
            doBreak = true
        }

        if doBreak == false && bytesRead == 0 {
            continue
        }

        if bytesRead > 0 {
            buffer.Write(incoming[:bytesRead])
            if bytes.HasSuffix(buffer.Bytes(), []byte("|")) {
                bb := bytes.Trim(buffer.Bytes(), "|")
                buffer.Reset()
                buffer.Write(bb)
                doBreak = true
            }
        }

        if doBreak {
            break
        }
    }
    return buffer
}

现在在我的情况下,如果我通过telnet连接(go代码还包括一个client()连接到的连接server()),并且我输入了一些类似test 12345|公平的东西,则一切正常,并且缓冲区包含了所有从telnet写入的字节(除非被删除的管道Trim()调用)。

如果我if bytes.HasSuffix(buffer.Bytes(), []byte("|")) {从代码中删除该块,那么我将在2秒后再次超时,这是按预期的,因为在该时间内没有接收到任何数据,并且服务器关闭了连接,并且如果我没有设置从连接后,它将永远等待读取数据,并且永远不知道何时停止。

我想我的问题是,如果我发送多个数据块,是否必须指定自己的分隔符,以便我知道何时停止从连接中读取并避免永远等待或等待服务器使连接超时?


阅读 324

收藏
2020-07-02

共1个答案

一尘不染

我想我的问题是,如果我发送多个数据块,是否必须指定自己的分隔符,以便我知道何时停止从连接中读取数据,并避免永远等待或等待服务器使连接超时

是。TCP是一种流协议,如果不对消息进行某种形式的框架化,就无法确定协议中消息的开始和停止位置。

使用的更常见的成帧方法是发送大小前缀,以便接收器 无需 缓冲结果并扫描定界符 即可
知道要读取多少内容。这可以很简单message_length:data....(另请参见netstringtype-
length-value
编码)。

2020-07-02