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