首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >优化网络代码

优化网络代码
EN

Stack Overflow用户
提问于 2017-01-26 00:32:36
回答 1查看 53关注 0票数 1

我有一个Go服务器,它接受来自大量TCP客户端的输入,这些客户端输入数据流。该格式是一种自定义格式,末尾分隔符可以出现在字节流中,因此它使用字节填充来解决此问题。

我正在寻找我的代码中的热点,这抛出了一个巨大的热点,我相信它可以变得更有效率,但我不太确定目前如何根据提供的Go函数。

下面是代码,pprof显示了popPacketFromBuffer命令的热点。这将在接收到每个字节之后查看当前缓冲区,并查找其自身的endDelimiter。如果一行中有2个,那么它就在数据包本身内。

我确实考虑过使用ReadBytes()而不是ReadByte(),但是看起来我需要指定一个分隔符,并且我担心这会切断中流中的数据包?而且,在任何情况下,这会比我正在做的事情更有效率吗?

popPacketFromBuffer函数中,for循环是热点。

有什么想法吗?

代码语言:javascript
运行
复制
// Read client data from channel
func (c *Client) listen() {

    reader := bufio.NewReader(c.conn)

    clientBuffer := new(bytes.Buffer)

    for {
        c.conn.SetDeadline(time.Now().Add(c.timeoutDuration))

        byte, err := reader.ReadByte()

        if err != nil {
            c.conn.Close()
            c.server.onClientConnectionClosed(c, err)
            return
        }

        wrErr := clientBuffer.WriteByte(byte)
        if wrErr != nil {
            log.Println("Write Error:", wrErr)
        }

        packet := popPacketFromBuffer(clientBuffer)
        if packet != nil {
            c.receiveMutex.Lock()
            packetSize := uint64(len(packet))
            c.bytesReceived += packetSize
            c.receiveMutex.Unlock()

            packetBuffer := bytes.NewBuffer(packet)

            b, err := uncompress(packetBuffer.Bytes())
            if err != nil {
                log.Println("Unzip Error:", err)
            } else {
                c.server.onNewMessage(c, b)
            }
        }

    }
}

func popPacketFromBuffer(buffer *bytes.Buffer) []byte {

    bufferLength := buffer.Len()

    if bufferLength >= 125000 { // 1MB in bytes is roughly this
        log.Println("Buffer is too large ", bufferLength)
        buffer.Reset()
        return nil
    }

    tempBuffer := buffer.Bytes()
    length := len(tempBuffer)

    // Return on zero length buffer submission
    if length == 0 {
        return nil
    }

    endOfPacket := -1

    // Determine the endOfPacket position by looking for an instance of our delimiter
    for i := 0; i < length-1; i++ {
        if tempBuffer[i] == endDelimiter {
            if tempBuffer[i+1] == endDelimiter {
                i++
            } else {
                // We found a single delimiter, so consider this the end of a packet
                endOfPacket = i - 2
                break
            }
        }
    }

    if endOfPacket != -1 {
        // Grab the contents of the provided packet
        extractedPacket := buffer.Bytes()

        // Extract the last byte as we were super greedy with the read operation to check for stuffing
        carryByte := extractedPacket[len(extractedPacket)-1]

        // Clear the main buffer now we have extracted a packet from it
        buffer.Reset()

        // Add the carryByte over to our new buffer
        buffer.WriteByte(carryByte)

        // Ensure packet begins with a valid startDelimiter
        if extractedPacket[0] != startDelimiter {
            log.Println("Popped a packet without a valid start delimiter")
            return nil
        }

        // Remove the start and end caps
        slice := extractedPacket[1 : len(extractedPacket)-2]

        return deStuffPacket(slice)
    }

    return nil
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-01-26 02:39:21

看起来您每次从connection接收到单个字节时都会调用popPacketFromBuffer()。但是,popPacketFromBuffer()复制空洞缓冲区并检查每个字节、每个类型的分隔符。也许这是压倒性的。对我来说,你不需要循环

代码语言:javascript
运行
复制
for i := 0; i < length-1; i++ {
        if tempBuffer[i] == endDelimiter {
            if tempBuffer[i+1] == endDelimiter {
                i++
            } else {
                // We found a single delimiter, so consider this the end of a packet
                endOfPacket = i - 2
                break
            }
        }
    }

popPacketFromBuffer()中,可能不是只测试最后两个字节而是循环

代码语言:javascript
运行
复制
if (buffer[len(buffer)-2] == endDelimiter) && (buffer[len(buffer)-1] != endDelimiter){
    //It's a packet
}

就足以达到目的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41856794

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档