github.com/wangyougui/gf/v2@v2.6.5/net/gtcp/gtcp_conn.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/wangyougui/gf. 6 7 package gtcp 8 9 import ( 10 "bufio" 11 "bytes" 12 "crypto/tls" 13 "io" 14 "net" 15 "time" 16 17 "github.com/wangyougui/gf/v2/errors/gerror" 18 ) 19 20 // Conn is the TCP connection object. 21 type Conn struct { 22 net.Conn // Underlying TCP connection object. 23 reader *bufio.Reader // Buffer reader for connection. 24 deadlineRecv time.Time // Timeout point for reading. 25 deadlineSend time.Time // Timeout point for writing. 26 bufferWaitRecv time.Duration // Interval duration for reading buffer. 27 } 28 29 const ( 30 // Default interval for reading buffer. 31 receiveAllWaitTimeout = time.Millisecond 32 ) 33 34 // NewConn creates and returns a new connection with given address. 35 func NewConn(addr string, timeout ...time.Duration) (*Conn, error) { 36 if conn, err := NewNetConn(addr, timeout...); err == nil { 37 return NewConnByNetConn(conn), nil 38 } else { 39 return nil, err 40 } 41 } 42 43 // NewConnTLS creates and returns a new TLS connection 44 // with given address and TLS configuration. 45 func NewConnTLS(addr string, tlsConfig *tls.Config) (*Conn, error) { 46 if conn, err := NewNetConnTLS(addr, tlsConfig); err == nil { 47 return NewConnByNetConn(conn), nil 48 } else { 49 return nil, err 50 } 51 } 52 53 // NewConnKeyCrt creates and returns a new TLS connection 54 // with given address and TLS certificate and key files. 55 func NewConnKeyCrt(addr, crtFile, keyFile string) (*Conn, error) { 56 if conn, err := NewNetConnKeyCrt(addr, crtFile, keyFile); err == nil { 57 return NewConnByNetConn(conn), nil 58 } else { 59 return nil, err 60 } 61 } 62 63 // NewConnByNetConn creates and returns a TCP connection object with given net.Conn object. 64 func NewConnByNetConn(conn net.Conn) *Conn { 65 return &Conn{ 66 Conn: conn, 67 reader: bufio.NewReader(conn), 68 deadlineRecv: time.Time{}, 69 deadlineSend: time.Time{}, 70 bufferWaitRecv: receiveAllWaitTimeout, 71 } 72 } 73 74 // Send writes data to remote address. 75 func (c *Conn) Send(data []byte, retry ...Retry) error { 76 for { 77 if _, err := c.Write(data); err != nil { 78 // Connection closed. 79 if err == io.EOF { 80 return err 81 } 82 // Still failed even after retrying. 83 if len(retry) == 0 || retry[0].Count == 0 { 84 err = gerror.Wrap(err, `Write data failed`) 85 return err 86 } 87 if len(retry) > 0 { 88 retry[0].Count-- 89 if retry[0].Interval == 0 { 90 retry[0].Interval = defaultRetryInternal 91 } 92 time.Sleep(retry[0].Interval) 93 } 94 } else { 95 return nil 96 } 97 } 98 } 99 100 // Recv receives and returns data from the connection. 101 // 102 // Note that, 103 // 1. If length = 0, which means it receives the data from current buffer and returns immediately. 104 // 2. If length < 0, which means it receives all data from connection and returns it until no data 105 // from connection. Developers should notice the package parsing yourself if you decide receiving 106 // all data from buffer. 107 // 3. If length > 0, which means it blocks reading data from connection until length size was received. 108 // It is the most commonly used length value for data receiving. 109 func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) { 110 var ( 111 err error // Reading error. 112 size int // Reading size. 113 index int // Received size. 114 buffer []byte // Buffer object. 115 bufferWait bool // Whether buffer reading timeout set. 116 ) 117 if length > 0 { 118 buffer = make([]byte, length) 119 } else { 120 buffer = make([]byte, defaultReadBufferSize) 121 } 122 123 for { 124 if length < 0 && index > 0 { 125 bufferWait = true 126 if err = c.SetReadDeadline(time.Now().Add(c.bufferWaitRecv)); err != nil { 127 err = gerror.Wrap(err, `SetReadDeadline for connection failed`) 128 return nil, err 129 } 130 } 131 size, err = c.reader.Read(buffer[index:]) 132 if size > 0 { 133 index += size 134 if length > 0 { 135 // It reads til `length` size if `length` is specified. 136 if index == length { 137 break 138 } 139 } else { 140 if index >= defaultReadBufferSize { 141 // If it exceeds the buffer size, it then automatically increases its buffer size. 142 buffer = append(buffer, make([]byte, defaultReadBufferSize)...) 143 } else { 144 // It returns immediately if received size is lesser than buffer size. 145 if !bufferWait { 146 break 147 } 148 } 149 } 150 } 151 if err != nil { 152 // Connection closed. 153 if err == io.EOF { 154 break 155 } 156 // Re-set the timeout when reading data. 157 if bufferWait && isTimeout(err) { 158 if err = c.SetReadDeadline(c.deadlineRecv); err != nil { 159 err = gerror.Wrap(err, `SetReadDeadline for connection failed`) 160 return nil, err 161 } 162 err = nil 163 break 164 } 165 if len(retry) > 0 { 166 // It fails even it retried. 167 if retry[0].Count == 0 { 168 break 169 } 170 retry[0].Count-- 171 if retry[0].Interval == 0 { 172 retry[0].Interval = defaultRetryInternal 173 } 174 time.Sleep(retry[0].Interval) 175 continue 176 } 177 break 178 } 179 // Just read once from buffer. 180 if length == 0 { 181 break 182 } 183 } 184 return buffer[:index], err 185 } 186 187 // RecvLine reads data from the connection until reads char '\n'. 188 // Note that the returned result does not contain the last char '\n'. 189 func (c *Conn) RecvLine(retry ...Retry) ([]byte, error) { 190 var ( 191 err error 192 buffer []byte 193 data = make([]byte, 0) 194 ) 195 for { 196 buffer, err = c.Recv(1, retry...) 197 if len(buffer) > 0 { 198 if buffer[0] == '\n' { 199 data = append(data, buffer[:len(buffer)-1]...) 200 break 201 } else { 202 data = append(data, buffer...) 203 } 204 } 205 if err != nil { 206 break 207 } 208 } 209 return data, err 210 } 211 212 // RecvTill reads data from the connection until reads bytes `til`. 213 // Note that the returned result contains the last bytes `til`. 214 func (c *Conn) RecvTill(til []byte, retry ...Retry) ([]byte, error) { 215 var ( 216 err error 217 buffer []byte 218 data = make([]byte, 0) 219 length = len(til) 220 ) 221 for { 222 buffer, err = c.Recv(1, retry...) 223 if len(buffer) > 0 { 224 if length > 0 && 225 len(data) >= length-1 && 226 buffer[0] == til[length-1] && 227 bytes.EqualFold(data[len(data)-length+1:], til[:length-1]) { 228 data = append(data, buffer...) 229 break 230 } else { 231 data = append(data, buffer...) 232 } 233 } 234 if err != nil { 235 break 236 } 237 } 238 return data, err 239 } 240 241 // RecvWithTimeout reads data from the connection with timeout. 242 func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) { 243 if err = c.SetDeadlineRecv(time.Now().Add(timeout)); err != nil { 244 return nil, err 245 } 246 defer func() { 247 _ = c.SetDeadlineRecv(time.Time{}) 248 }() 249 data, err = c.Recv(length, retry...) 250 return 251 } 252 253 // SendWithTimeout writes data to the connection with timeout. 254 func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) { 255 if err = c.SetDeadlineSend(time.Now().Add(timeout)); err != nil { 256 return err 257 } 258 defer func() { 259 _ = c.SetDeadlineSend(time.Time{}) 260 }() 261 err = c.Send(data, retry...) 262 return 263 } 264 265 // SendRecv writes data to the connection and blocks reading response. 266 func (c *Conn) SendRecv(data []byte, length int, retry ...Retry) ([]byte, error) { 267 if err := c.Send(data, retry...); err == nil { 268 return c.Recv(length, retry...) 269 } else { 270 return nil, err 271 } 272 } 273 274 // SendRecvWithTimeout writes data to the connection and reads response with timeout. 275 func (c *Conn) SendRecvWithTimeout(data []byte, length int, timeout time.Duration, retry ...Retry) ([]byte, error) { 276 if err := c.Send(data, retry...); err == nil { 277 return c.RecvWithTimeout(length, timeout, retry...) 278 } else { 279 return nil, err 280 } 281 } 282 283 // SetDeadline sets the deadline for current connection. 284 func (c *Conn) SetDeadline(t time.Time) (err error) { 285 if err = c.Conn.SetDeadline(t); err == nil { 286 c.deadlineRecv = t 287 c.deadlineSend = t 288 } 289 if err != nil { 290 err = gerror.Wrapf(err, `SetDeadline for connection failed with "%s"`, t) 291 } 292 return err 293 } 294 295 // SetDeadlineRecv sets the deadline of receiving for current connection. 296 func (c *Conn) SetDeadlineRecv(t time.Time) (err error) { 297 if err = c.SetReadDeadline(t); err == nil { 298 c.deadlineRecv = t 299 } 300 if err != nil { 301 err = gerror.Wrapf(err, `SetDeadlineRecv for connection failed with "%s"`, t) 302 } 303 return err 304 } 305 306 // SetDeadlineSend sets the deadline of sending for current connection. 307 func (c *Conn) SetDeadlineSend(t time.Time) (err error) { 308 if err = c.SetWriteDeadline(t); err == nil { 309 c.deadlineSend = t 310 } 311 if err != nil { 312 err = gerror.Wrapf(err, `SetDeadlineSend for connection failed with "%s"`, t) 313 } 314 return err 315 } 316 317 // SetBufferWaitRecv sets the buffer waiting timeout when reading all data from connection. 318 // The waiting duration cannot be too long which might delay receiving data from remote address. 319 func (c *Conn) SetBufferWaitRecv(bufferWaitDuration time.Duration) { 320 c.bufferWaitRecv = bufferWaitDuration 321 }