什么是使用net.Conn.Read持久TCP套接字的正确方法

时间:2017-12-01 01:18:58

标签: sockets go tcp

我的Go服务器上有一个有效的TCP套接字设置。我接受传入连接,运行for循环并使用net.Conn.Read函数读取传入数据。

但这对我来说没有意义。如何知道已收到完整的消息以便继续返回消息大小?

这是我目前的代码:

void HomeScreen(Button& sender) {
    Serial.println(sender.getSpanX()); //Prints some number like 2133411092 but varies every time. Should be 200.
    Serial.println(sender.theZone.getSpanX()); //Constantly prints 85, but should also be 200.
    sender.disable();
    theScreen.fillScr(VGA_MAROON);
    delay(300);
    theScreen.fillScr(VGA_WHITE);
    Serial.println(sender.getX()); //Usually prints some number like -149863422 but varies every time
    sender.resize(sender.getX(), 10, sender.getSpanX(), sender.getSpanY()); //The button disappears on the screen, which it should not.
    sender.enable();

}

让我们说我的应用程序发送一个长度为6个字节的消息(可以是任何大小)。 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)) } } } 如何知道它何时收到所述消息的结束然后继续?

我的经验主要在于C#,所以Go在这里很不寻常。对于我的C#应用​​程序,消息具有第一个字节中包含的消息大小,然后我使用for循环读取剩余字节直到消息大小。

然而Go中的上述代码似乎得到了完整的消息并继续 - 它有些自动知道我的消息的大小?

我真的很困惑这是怎么回事,或者当我真正接近错误的时候,它只是运气好。

我的所有消息都在第一个字节中有标题,说明消息的大小。但似乎我在Go服务器上不需要它,我误解了它是如何工作的?

1 个答案:

答案 0 :(得分:6)

TCP不提供任何消息框架,您可以根据您定义的任何协议缓冲流并解析消息。

在解析TCP流时,立即将连接包装在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)])
}