泄漏的读取器与紧密循环

huangapple go评论119阅读模式
英文:

Leaking Reader with tight loop

问题

我有以下代码,我认为它泄漏严重。分析它后,我怀疑 defer r.Close() 从未被调用。

在这里,是否有更好的使用 Reader 和 gzip 的方法?

// 从通道读取客户端数据
func (c *Client) listen() {
timeoutDuration := 30 * time.Second

reader := bufio.NewReader(c.conn)

clientBuffer := new(bytes.Buffer)

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

    byte, err := reader.ReadByte()

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

    clientBuffer.WriteByte(byte)
    packet := popPacketFromBuffer(clientBuffer)

    if packet != nil {
        packetBuffer := bytes.NewBuffer(packet)

        r, _ := gzip.NewReader(packetBuffer)
        defer r.Close()

        b, err := ioutil.ReadAll(r)
        if err != nil {
            log.Fatal(err)
        }

        c.server.onNewMessage(c, b)
    }

}

}

英文:

I have the following code that I think is leaking heavily. And analysing it I suspect that the defer r.Close() is never called.

Would there be a better way of using the Reader and gzip here at all?

// Read client data from channel
func (c *Client) listen() {
	timeoutDuration := 30 * time.Second

	reader := bufio.NewReader(c.conn)

	clientBuffer := new(bytes.Buffer)

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

		byte, err := reader.ReadByte()

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

		clientBuffer.WriteByte(byte)
		packet := popPacketFromBuffer(clientBuffer)

		if packet != nil {
			packetBuffer := bytes.NewBuffer(packet)

			r, _ := gzip.NewReader(packetBuffer)
			defer r.Close()

			b, err := ioutil.ReadAll(r)
			if err != nil {
				log.Fatal(err)
			}

			c.server.onNewMessage(c, b)
		}

	}
}

答案1

得分: 3

你的问题是defer函数只会在函数结束时调用,而不是在循环中调用。所以,是的,它们可能会保持打开状态。

一种方法是将紧密循环封装到一个函数中。

func uncompress(packet []byte) ([]byte, error) {
    r, _ := gzip.NewReader(bytes.NewBuffer(packet))
    defer r.Close()
    return ioutil.ReadAll(r)
}

// 从通道读取客户端数据
func (c *Client) listen() {
    /* … */

    for {
        /* … */

        if packet != nil {
            b, err := uncompress(packet)
            if err != nil {
                log.Fatal(err)
            }
            c.server.onNewMessage(c, b)
        }

    }
}

另一种方法是展开defer调用并手动关闭。

// 从通道读取客户端数据
func (c *Client) listen() {
    /* … */

    for {
        /* … */

        if packet != nil {
            r, _ := gzip.NewReader(bytes.NewBuffer(packet))
            b, err := ioutil.ReadAll(r)
            if err != nil {
                log.Fatal(err)
            }
            r.Close()
            c.server.onNewMessage(c, b)
        }

    }
}
英文:

Your problem is that defer functions are only called at the end of the function. Not the loop. So, yes, it is probable that they stay open.

One method would be to encapsulate your tight-loop into a function.

func uncompress(packet []byte) ([]byte, error) {
    r, _ := gzip.NewReader(bytes.NewBuffer(packet))
    defer r.Close()
    return ioutil.ReadAll(r)
}

// Read client data from channel
func (c *Client) listen() {
    /* … */

    for {
        /* … */

        if packet != nil {
            b, err := uncompress(packet)
            if err != nil {
                log.Fatal(err)
            }
            c.server.onNewMessage(c, b)
        }

    }
}

Another would be to unroll the defer call and do it manually.

// Read client data from channel
func (c *Client) listen() {
    /* … */

    for {
        /* … */

        if packet != nil {
            r, _ := gzip.NewReader(bytes.NewBuffer(packet))
            b, err := ioutil.ReadAll(r)
            if err != nil {
                log.Fatal(err)
            }
            r.Close()
            c.server.onNewMessage(c, b)
        }

    }
}

huangapple
  • 本文由 发表于 2017年1月14日 01:11:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/41639955.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定