当前位置: 首页 > 面试题库 >

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

翟缪文
2023-03-14
问题内容

我的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中的上述代码似乎可以获取完整的消息并继续执行-它是如何自动知道消息大小的?

我真的很困惑这是怎么发生的,或者当我实际上错误地对待它时,如果运气很好。

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


问题答案:

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


 类似资料:
  • 所以,我尝试使用套接字和Ruby来模拟一些基本的HTTP持久性连接——用于大学课堂。 关键是构建一个服务器——能够处理多个客户端——接收文件路径并返回文件内容——就像HTTP GET一样。 当前服务器实现循环监听客户端,当有传入连接时触发新线程,并从该套接字读取文件路径。它非常笨,但是在处理非持久连接时工作良好——每个连接一个请求。 但它们应该坚持不懈。 这意味着客户端不必担心关闭连接。在非持久版

  • 问题内容: 我有一个简单的班级角色: 现在,我想重写其方法equals和hashCode。我的第一个建议是: 但是,当我创建新的Role对象时,其id为null。这就是为什么我对hashCode方法实现有一些问题。现在,我可以简单地返回,但是如果没有RoleName字段,该怎么办?我几乎可以肯定,组成更复杂的示例并不难,而通过返回其字段之一的hashCode不能解决该示例。 因此,我想查看一些指向

  • 问题内容: 从我的理解在这里,“V8拥有世代垃圾收集器。物件的移动风靡随机,节点不能得到一个指向原始字符串数据写入到插座。” 因此,我不应该将来自TCP流的数据存储在字符串中,特别是当该字符串变得大于字节时。(希望我到目前为止是..) 那么,处理来自TCP套接字的所有数据的最佳方法是什么?到目前为止,我一直在尝试用作定界符,因为我认为它在某种程度上是唯一的,不会缠结其他事物。 将要收集的数据样本是

  • 问题内容: 我要进行Flask + Nginx + Gunicorn部署。我已经安装并正在运行Nginx,并且按照文档中的说明运行gunicorn: 但是,当我注销服务器时,gunicorn进程退出了吗?确保Nginx保持连接状态并在崩溃时重新启动的正确方法是什么? 问题答案: 运行Gunicorn时使用选项。例:

  • 问题内容: 我使用10gen的本机node.js驱动器将mongodb(2.2.2)与node.js一起使用。 起初一切顺利。但是当涉及到并发基准测试部分时,会发生很多错误。频繁进行1000次并发连接/关闭可能会导致mongodb拒绝任何进一步的请求,并出现以下错误: 另外,如果许多客户端在没有显式关闭的情况下关闭,则mongodb将花费几分钟的时间来检测并关闭它们。这也将导致类似的连接问题。(使

  • 我试试看。js与mongodb(2.2.2)一起使用本机节点。js drive by 10gen。 起初一切都很顺利。但在并发基准测试部分,出现了很多错误。频繁连接/关闭1000次并发可能会导致mongodb拒绝任何进一步的请求,错误如下: 此外,如果很多客户端在没有显式关闭的情况下关闭,mongodb需要几分钟来检测并关闭它们。这也会导致类似的连接问题。(使用/var/log/mongodb/m