如何在客户端通过 TCP 连接发送的一条消息中读取所有数据而不会在 Go 中阻塞?

我正在 Go 中实现一个协议的服务器。在该协议中,客户端连接到服务器并可以发送一堆命令,并在每个命令发送后期待服务器的响应。命令消息的格式如下:COMMAND <BODY_LENGTH>\r\n BODY\r\n,其中 BODY_LENGTH 是任意的,并在命令行中指定。


我解析命令的方式是:从 中读取前几个字节net.Conn,解析命令和正文长度,并用另一个读取读取整个正文,处理消息,发送响应,并循环等待下一个命令消息连接:


func handler(c net.Conn) {

    defer c.Close()

    for {

        msg := make([]byte, 1024)


        n, err := c.Read(msg)

        cmd, bodyLength = parseCommand(msg)

        // read the body of body length here

        if err == io.EOF {

            fmt.Printf("Client has closed the connection")

            break

        } 


        response := handleCommand(cmd, body)

        n, err := c.Write(response)

        if err != nil {

            fmt.Printf("ERROR: write\n")

            fmt.Print(err)

        }

        fmt.Printf("SERVER: sent %v bytes\n", n)

    }

}

我假设(Go 文档对此不清楚)net.Conn.Read()在等待来自客户端的下一条消息时阻塞,并且仅在客户端关闭连接时返回 io.EOF。如果我错了,请纠正我。


如果命令格式正确,则一切正常。但是如果命令格式错误,并且我在第一行没有得到正文长度,我希望我仍然可以读取消息的其余部分,丢弃它,然后等待下一条可能有效的消息。问题是,如果我不知道预期的数据长度,我可能会启动一个 read(),如果我刚刚读取了最后一个字节,它就会阻塞。


如何在不知道其长度的情况下读取整个消息(缓冲的所有内容)?或者我是否必须关闭连接,并告诉客户端为下一个命令启动一个新连接?


jeck猫
浏览 213回答 1
1回答

holdtom

TCP 中没有消息这样的东西。不能保证单个发送的所有字节send()都会一起到达,或者它们都适合接收器的套接字接收缓冲区。因此,您的目标是不可能实现的。这也是毫无意义的。在整个命令到达之前你不能做任何事情,无论如何你肯定会在命令之间阻塞。在接收命令期间阻塞不会造成任何进一步的伤害。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go