sockets - 将 net.Conn.Read 用于持久 TCP 套接字的正确方法是什么

标签 sockets go tcp

我的 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 如何知道它何时收到所述消息的结尾然后继续?

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

但是 Go 中的上述代码似乎获得了完整的消息并继续 - 它如何自动知道我的消息的大小?

我真的很困惑这是怎么发生的,或者当我实际上接近错误时它是否只是运气好。

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

最佳答案

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

解析 TCP 流时,立即将连接包装在 bufio.Reader 中通常很有用。 ,因为它不仅可以提高阅读效率,还可以为您提供更多有用的方法。您可以如何解析协议(protocol)的示例如下:

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)])
}

关于sockets - 将 net.Conn.Read 用于持久 TCP 套接字的正确方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47585244/

相关文章:

macos - 如何对 Go 工作区进行碎片化

go - nsq go 客户端跟不上

python - 带有 Python : How to optimize my implementation? 的 TCP 服务器

linux - 在没有 root 访问权限的情况下监控特定端口上的流量(计算传输的字节数)

c++ - 通过 tcp 中继目录树的最有效方法是什么? C++

Java 程序不会传输大于 64KB 的文件

java - java.net.SocketException : Connection reset and java.net.SocketException : Broken Pipe? 有什么区别

maven - 如何确定 docker exec 中的命令何时完成

java - 无法从输出流读取

c# - C# 中的一个非常简单的 TCP 服务器/客户端偶尔会丢弃数据包。我能做些什么来防止这种情况发生?