diff --git a/client.go b/client.go index e9af07b..a07764c 100644 --- a/client.go +++ b/client.go @@ -71,8 +71,8 @@ func (c *ClientConn) UnreadByte() error { } func (c *ClientConn) Flush() error { - c.m.Lock() - defer c.m.Unlock() + // c.m.Lock() + // defer c.m.Unlock() return c.bw.Flush() } @@ -85,8 +85,8 @@ func (c *ClientConn) Read(buf []byte) (int, error) { } func (c *ClientConn) Write(buf []byte) (int, error) { - c.m.Lock() - defer c.m.Unlock() + // c.m.Lock() + // defer c.m.Unlock() return c.bw.Write(buf) } diff --git a/encoding.go b/encoding.go index 384e926..21acf60 100644 --- a/encoding.go +++ b/encoding.go @@ -9,6 +9,7 @@ import ( "image/draw" "image/png" "io" + "sync" ) // EncodingType represents a known VNC encoding type. @@ -85,6 +86,15 @@ const ( TightFilterGradient TightFilter = 2 ) +var bPool = sync.Pool{ + New: func() interface{} { + // The Pool's New function should generally only return pointer + // types, since a pointer can be put into the return interface + // value without an allocation: + return new(bytes.Buffer) + }, +} + type Encoding interface { Type() EncodingType Read(Conn, *Rectangle) error @@ -197,14 +207,18 @@ func (enc *TightPngEncoding) Write(c Conn, rect *Rectangle) error { cmp := enc.TightCC.Compression switch cmp { case TightCompressionPNG: - buf := bytes.NewBuffer(nil) - if err := png.Encode(buf, enc.Image); err != nil { + buf := bPool.Get().(*bytes.Buffer) + buf.Reset() + defer bPool.Put(buf) + pngEnc := &png.Encoder{CompressionLevel: png.BestSpeed} + if err := pngEnc.Encode(buf, enc.Image); err != nil { return err } if err := writeTightLength(c, buf.Len()); err != nil { return err } - if _, err := io.Copy(c, buf); err != nil { + + if _, err := buf.WriteTo(c); err != nil { return err } case TightCompressionFill: @@ -311,8 +325,9 @@ func readTightLength(c Conn) (int, error) { } func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error { - buf := bytes.NewBuffer(nil) - defer buf.Reset() + buf := bPool.Get().(*bytes.Buffer) + buf.Reset() + defer bPool.Put(buf) n := 0 for _, c := range enc.Colors { bytes, err := c.Marshal() @@ -325,13 +340,16 @@ func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error { return err } } - _, err := c.Write(buf.Bytes()) + + _, err := buf.WriteTo(c) return err } // Read implements the Encoding interface. func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error { - buf := bytes.NewBuffer(nil) + buf := bPool.Get().(*bytes.Buffer) + buf.Reset() + defer bPool.Put(buf) pf := c.PixelFormat() cm := c.ColorMap() bytesPerPixel := int(pf.BPP / 8) @@ -341,7 +359,6 @@ func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error { return err } buf.Write(data) - defer buf.Reset() colors := make([]Color, rect.Area()) for y := uint16(0); y < rect.Height; y++ { for x := uint16(0); x < rect.Width; x++ { diff --git a/pixel_format.go b/pixel_format.go index b0d23fb..7256eb0 100644 --- a/pixel_format.go +++ b/pixel_format.go @@ -93,7 +93,10 @@ func (pf *PixelFormat) Marshal() ([]byte, error) { } // Create the slice of bytes - buf := bytes.NewBuffer(nil) + buf := bPool.Get().(*bytes.Buffer) + buf.Reset() + defer bPool.Put(buf) + if err := binary.Write(buf, binary.BigEndian, &pf); err != nil { return nil, err } @@ -112,7 +115,13 @@ func (pf *PixelFormat) Read(r io.Reader) error { // Unmarshal implements the Unmarshaler interface. func (pf *PixelFormat) Unmarshal(data []byte) error { - buf := bytes.NewBuffer(data) + buf := bPool.Get().(*bytes.Buffer) + buf.Reset() + defer bPool.Put(buf) + + if _, err := buf.Write(data); err != nil { + return err + } var msg PixelFormat if err := binary.Read(buf, binary.BigEndian, &msg); err != nil { diff --git a/server.go b/server.go index cd3dc9b..0ee18fb 100644 --- a/server.go +++ b/server.go @@ -53,8 +53,8 @@ func (c *ServerConn) SetProtoVersion(pv string) { } func (c *ServerConn) Flush() error { - c.m.Lock() - defer c.m.Unlock() + // c.m.Lock() + // defer c.m.Unlock() return c.bw.Flush() } @@ -76,8 +76,8 @@ func (c *ServerConn) Read(buf []byte) (int, error) { } func (c *ServerConn) Write(buf []byte) (int, error) { - c.m.Lock() - defer c.m.Unlock() + // c.m.Lock() + // defer c.m.Unlock() return c.bw.Write(buf) }