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  }