我的Go服务器上有一个有效的TCP套接字设置。我接受传入连接,运行for循环并使用net.Conn.Read函数读取传入数据。
但这对我来说毫无意义。如何知道已收到完整的消息以便继续返回消息大小?
这是我目前的代码:
func (tcpSocket *TCPServer) HandleConnection(conn net.Conn) { println("Handling connection! ", conn.RemoteAddr().String(), " connected!") recieveBuffer := make([]byte, 50) // largest message we ever get is 50 bytes defer func() { fmt.Println("Closing connection for: ", conn.RemoteAddr().String()) conn.Close() }() for { // how does it know the end of a message vs the start of a new one? messageSize, err := conn.Read(recieveBuffer) if err != nil { return } if messageSize > 0 { // update keep alive since we got a message conn.SetReadDeadline(time.Now().Add(time.Second * 5)) } } }
可以说我的应用程序发送的消息长度为6个字节(可以是任意大小)。怎么conn.Read知道收到消息后才继续呢?
conn.Read
我的经验主要在于C#,所以Go在这里并不常见。对于我的C#应用程序,消息具有第一个字节中包含的消息大小,然后使用for循环读取直到消息大小为止的其余字节。
但是,Go中的上述代码似乎可以获取完整的消息并继续执行-它是如何自动知道消息大小的?
我真的很困惑这是怎么发生的,或者当我实际上错误地对待它时,如果运气很好。
我所有的消息在第一个字节中都有标头,说明消息的大小。但似乎我在Go服务器上不需要它,我是否误解了它的工作原理?
TCP不提供任何消息框架,而是由您来缓冲流并根据定义的协议解析消息。
解析TCP流时,将连接立即包装在中通常是有用的bufio.Reader,因为它不仅可以使读取更加有效,而且可以为您提供更多有用的方法。如何解析协议的示例可能是:
bufio.Reader
buff := make([]byte, 50) c := bufio.NewReader(conn) for { // read a single byte which contains the message length size, err := c.ReadByte() if err != nil { return err } // read the full message, or return an error _, err := io.ReadFull(c, buff[:int(size)]) if err != nil { return err } fmt.Printf("received %x\n", buff[:int(size)]) }