github.com/gogf/gf@v1.16.9/net/gtcp/gtcp_pool.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gtcp 8 9 import ( 10 "time" 11 12 "github.com/gogf/gf/container/gmap" 13 "github.com/gogf/gf/container/gpool" 14 ) 15 16 // PoolConn is a connection with pool feature for TCP. 17 // Note that it is NOT a pool or connection manager, it is just a TCP connection object. 18 type PoolConn struct { 19 *Conn // Underlying connection object. 20 pool *gpool.Pool // Connection pool, which is not a real connection pool, but a connection reusable pool. 21 status int // Status of current connection, which is used to mark this connection usable or not. 22 } 23 24 const ( 25 defaultPoolExpire = 10 * time.Second // Default TTL for connection in the pool. 26 connStatusUnknown = 0 // Means it is unknown it's connective or not. 27 connStatusActive = 1 // Means it is now connective. 28 connStatusError = 2 // Means it should be closed and removed from pool. 29 ) 30 31 var ( 32 // addressPoolMap is a mapping for address to its pool object. 33 addressPoolMap = gmap.NewStrAnyMap(true) 34 ) 35 36 // NewPoolConn creates and returns a connection with pool feature. 37 func NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) { 38 v := addressPoolMap.GetOrSetFuncLock(addr, func() interface{} { 39 var pool *gpool.Pool 40 pool = gpool.New(defaultPoolExpire, func() (interface{}, error) { 41 if conn, err := NewConn(addr, timeout...); err == nil { 42 return &PoolConn{conn, pool, connStatusActive}, nil 43 } else { 44 return nil, err 45 } 46 }) 47 return pool 48 }) 49 if v, err := v.(*gpool.Pool).Get(); err == nil { 50 return v.(*PoolConn), nil 51 } else { 52 return nil, err 53 } 54 } 55 56 // Close puts back the connection to the pool if it's active, 57 // or closes the connection if it's not active. 58 // 59 // Note that, if <c> calls Close function closing itself, <c> can not 60 // be used again. 61 func (c *PoolConn) Close() error { 62 if c.pool != nil && c.status == connStatusActive { 63 c.status = connStatusUnknown 64 c.pool.Put(c) 65 } else { 66 return c.Conn.Close() 67 } 68 return nil 69 } 70 71 // Send writes data to the connection. It retrieves a new connection from its pool if it fails 72 // writing data. 73 func (c *PoolConn) Send(data []byte, retry ...Retry) error { 74 err := c.Conn.Send(data, retry...) 75 if err != nil && c.status == connStatusUnknown { 76 if v, e := c.pool.Get(); e == nil { 77 c.Conn = v.(*PoolConn).Conn 78 err = c.Send(data, retry...) 79 } else { 80 err = e 81 } 82 } 83 if err != nil { 84 c.status = connStatusError 85 } else { 86 c.status = connStatusActive 87 } 88 return err 89 } 90 91 // Recv receives data from the connection. 92 func (c *PoolConn) Recv(length int, retry ...Retry) ([]byte, error) { 93 data, err := c.Conn.Recv(length, retry...) 94 if err != nil { 95 c.status = connStatusError 96 } else { 97 c.status = connStatusActive 98 } 99 return data, err 100 } 101 102 // RecvLine reads data from the connection until reads char '\n'. 103 // Note that the returned result does not contain the last char '\n'. 104 func (c *PoolConn) RecvLine(retry ...Retry) ([]byte, error) { 105 data, err := c.Conn.RecvLine(retry...) 106 if err != nil { 107 c.status = connStatusError 108 } else { 109 c.status = connStatusActive 110 } 111 return data, err 112 } 113 114 // RecvTil reads data from the connection until reads bytes <til>. 115 // Note that the returned result contains the last bytes <til>. 116 func (c *PoolConn) RecvTil(til []byte, retry ...Retry) ([]byte, error) { 117 data, err := c.Conn.RecvTil(til, retry...) 118 if err != nil { 119 c.status = connStatusError 120 } else { 121 c.status = connStatusActive 122 } 123 return data, err 124 } 125 126 // RecvWithTimeout reads data from the connection with timeout. 127 func (c *PoolConn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) { 128 if err := c.SetreceiveDeadline(time.Now().Add(timeout)); err != nil { 129 return nil, err 130 } 131 defer c.SetreceiveDeadline(time.Time{}) 132 data, err = c.Recv(length, retry...) 133 return 134 } 135 136 // SendWithTimeout writes data to the connection with timeout. 137 func (c *PoolConn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) { 138 if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil { 139 return err 140 } 141 defer c.SetSendDeadline(time.Time{}) 142 err = c.Send(data, retry...) 143 return 144 } 145 146 // SendRecv writes data to the connection and blocks reading response. 147 func (c *PoolConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) { 148 if err := c.Send(data, retry...); err == nil { 149 return c.Recv(receive, retry...) 150 } else { 151 return nil, err 152 } 153 } 154 155 // SendRecvWithTimeout writes data to the connection and reads response with timeout. 156 func (c *PoolConn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) { 157 if err := c.Send(data, retry...); err == nil { 158 return c.RecvWithTimeout(receive, timeout, retry...) 159 } else { 160 return nil, err 161 } 162 }