github.com/zhongdalu/gf@v1.0.0/g/net/gtcp/gtcp_conn.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/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/zhongdalu/gf/g/errors/gerror"
    18  )
    19  
    20  // 封装的链接对象
    21  type Conn struct {
    22  	net.Conn                     // 底层tcp对象
    23  	reader         *bufio.Reader // 当前链接的缓冲读取对象
    24  	buffer         []byte        // 读取缓冲区(用于数据读取时的缓冲区处理)
    25  	recvDeadline   time.Time     // 读取超时时间
    26  	sendDeadline   time.Time     // 写入超时时间
    27  	recvBufferWait time.Duration // 读取全部缓冲区数据时,读取缓冲区完毕后的等待间隔
    28  }
    29  
    30  const (
    31  	// 读取全部缓冲数据时,没有缓冲数据时的等待间隔
    32  	gRECV_ALL_WAIT_TIMEOUT = time.Millisecond
    33  )
    34  
    35  // 创建TCP链接
    36  func NewConn(addr string, timeout ...int) (*Conn, error) {
    37  	if conn, err := NewNetConn(addr, timeout...); err == nil {
    38  		return NewConnByNetConn(conn), nil
    39  	} else {
    40  		return nil, err
    41  	}
    42  }
    43  
    44  // 创建支持TLS加密通信的TCP链接
    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  // 根据证书和密钥文件创建支持TLS加密通信的TCP链接
    54  func NewConnKeyCrt(addr, crtFile, keyFile string) (*Conn, error) {
    55  	if conn, err := NewNetConnKeyCrt(addr, crtFile, keyFile); err == nil {
    56  		return NewConnByNetConn(conn), nil
    57  	} else {
    58  		return nil, err
    59  	}
    60  }
    61  
    62  // 将net.Conn接口对象转换为*gtcp.Conn对象
    63  func NewConnByNetConn(conn net.Conn) *Conn {
    64  	return &Conn{
    65  		Conn:           conn,
    66  		reader:         bufio.NewReader(conn),
    67  		recvDeadline:   time.Time{},
    68  		sendDeadline:   time.Time{},
    69  		recvBufferWait: gRECV_ALL_WAIT_TIMEOUT,
    70  	}
    71  }
    72  
    73  // 发送数据
    74  func (c *Conn) Send(data []byte, retry ...Retry) error {
    75  	for {
    76  		if _, err := c.Write(data); err != nil {
    77  			// 链接已关闭
    78  			if err == io.EOF {
    79  				return err
    80  			}
    81  			// 其他错误,重试之后仍不能成功
    82  			if len(retry) == 0 || retry[0].Count == 0 {
    83  				return err
    84  			}
    85  			if len(retry) > 0 {
    86  				retry[0].Count--
    87  				if retry[0].Interval == 0 {
    88  					retry[0].Interval = gDEFAULT_RETRY_INTERVAL
    89  				}
    90  				time.Sleep(time.Duration(retry[0].Interval) * time.Millisecond)
    91  			}
    92  		} else {
    93  			return nil
    94  		}
    95  	}
    96  }
    97  
    98  // 阻塞等待获取指定读取的数据长度,并给定重试策略。
    99  //
   100  // 需要注意:
   101  // 1、往往在socket通信中需要指定固定的数据结构,并在设定对应的长度字段,并在读取数据时便于区分包大小;
   102  // 2、当length < 0时表示获取缓冲区所有的数据,但是可能会引起包解析问题(可能出现粘包/断包情况),因此需要解析端注意解析策略;
   103  // 3、当length = 0时表示获取一次缓冲区的数据后立即返回;
   104  func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {
   105  	var err error       // 读取错误
   106  	var size int        // 读取长度
   107  	var index int       // 已读取长度
   108  	var buffer []byte   // 读取缓冲区
   109  	var bufferWait bool // 是否设置读取的超时时间
   110  
   111  	if length > 0 {
   112  		buffer = make([]byte, length)
   113  	} else {
   114  		buffer = make([]byte, gDEFAULT_READ_BUFFER_SIZE)
   115  	}
   116  
   117  	for {
   118  		// 缓冲区数据写入等待处理。
   119  		// 如果已经读取到数据(这点很关键,表明缓冲区已经有数据,剩下的操作就是将所有数据读取完毕),
   120  		// 那么可以设置读取全部缓冲数据的超时时间;如果没有接收到任何数据,那么将会进入读取阻塞(或者自定义的超时阻塞);
   121  		// 仅对读取全部缓冲区数据操作有效
   122  		if length < 0 && index > 0 {
   123  			bufferWait = true
   124  			if err = c.SetReadDeadline(time.Now().Add(c.recvBufferWait)); err != nil {
   125  				return nil, err
   126  			}
   127  		}
   128  		size, err = c.reader.Read(buffer[index:])
   129  		if size > 0 {
   130  			index += size
   131  			if length > 0 {
   132  				// 如果指定了读取大小,那么必须读取到指定长度才返回
   133  				if index == length {
   134  					break
   135  				}
   136  			} else {
   137  				if index >= gDEFAULT_READ_BUFFER_SIZE {
   138  					// 如果长度超过了自定义的读取缓冲区,那么自动增长
   139  					buffer = append(buffer, make([]byte, gDEFAULT_READ_BUFFER_SIZE)...)
   140  				} else {
   141  					// 如果第一次读取的数据并未达到缓冲变量长度,那么直接返回
   142  					if !bufferWait {
   143  						break
   144  					}
   145  				}
   146  			}
   147  		}
   148  		if err != nil {
   149  			// 链接已关闭
   150  			if err == io.EOF {
   151  				break
   152  			}
   153  			// 判断数据是否全部读取完毕(由于超时机制的存在,获取的数据完整性不可靠)
   154  			if bufferWait && isTimeout(err) {
   155  				if err = c.SetReadDeadline(c.recvDeadline); err != nil {
   156  					return nil, err
   157  				}
   158  				err = nil
   159  				break
   160  			}
   161  			if len(retry) > 0 {
   162  				// 其他错误,重试之后仍不能成功
   163  				if retry[0].Count == 0 {
   164  					break
   165  				}
   166  				retry[0].Count--
   167  				if retry[0].Interval == 0 {
   168  					retry[0].Interval = gDEFAULT_RETRY_INTERVAL
   169  				}
   170  				time.Sleep(time.Duration(retry[0].Interval) * time.Millisecond)
   171  				continue
   172  			}
   173  			break
   174  		}
   175  		// 只获取一次数据
   176  		if length == 0 {
   177  			break
   178  		}
   179  	}
   180  	return buffer[:index], err
   181  }
   182  
   183  // 按行读取数据,阻塞读取,直到完成一行读取位置(末尾以'\n'结尾,返回数据不包含换行符)
   184  func (c *Conn) RecvLine(retry ...Retry) ([]byte, error) {
   185  	var err error
   186  	var buffer []byte
   187  	data := make([]byte, 0)
   188  	for {
   189  		buffer, err = c.Recv(1, retry...)
   190  		if len(buffer) > 0 {
   191  			data = append(data, buffer...)
   192  			if buffer[0] == '\n' {
   193  				break
   194  			}
   195  		}
   196  		if err != nil {
   197  			break
   198  		}
   199  	}
   200  	if len(data) > 0 {
   201  		data = bytes.TrimRight(data, "\n\r")
   202  	}
   203  	return data, err
   204  }
   205  
   206  // 带超时时间的数据获取
   207  func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
   208  	if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
   209  		return nil, err
   210  	}
   211  	defer func() {
   212  		err = gerror.Wrap(c.SetRecvDeadline(time.Time{}), "SetRecvDeadline error")
   213  	}()
   214  	data, err = c.Recv(length, retry...)
   215  	return
   216  }
   217  
   218  // 带超时时间的数据发送
   219  func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
   220  	if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
   221  		return err
   222  	}
   223  	defer func() {
   224  		err = gerror.Wrap(c.SetSendDeadline(time.Time{}), "SetSendDeadline error")
   225  	}()
   226  	err = c.Send(data, retry...)
   227  	return
   228  }
   229  
   230  // 发送数据并等待接收返回数据
   231  func (c *Conn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
   232  	if err := c.Send(data, retry...); err == nil {
   233  		return c.Recv(receive, retry...)
   234  	} else {
   235  		return nil, err
   236  	}
   237  }
   238  
   239  // 发送数据并等待接收返回数据(带返回超时等待时间)
   240  func (c *Conn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
   241  	if err := c.Send(data, retry...); err == nil {
   242  		return c.RecvWithTimeout(receive, timeout, retry...)
   243  	} else {
   244  		return nil, err
   245  	}
   246  }
   247  
   248  func (c *Conn) SetDeadline(t time.Time) error {
   249  	err := c.Conn.SetDeadline(t)
   250  	if err == nil {
   251  		c.recvDeadline = t
   252  		c.sendDeadline = t
   253  	}
   254  	return err
   255  }
   256  
   257  func (c *Conn) SetRecvDeadline(t time.Time) error {
   258  	err := c.SetReadDeadline(t)
   259  	if err == nil {
   260  		c.recvDeadline = t
   261  	}
   262  	return err
   263  }
   264  
   265  func (c *Conn) SetSendDeadline(t time.Time) error {
   266  	err := c.SetWriteDeadline(t)
   267  	if err == nil {
   268  		c.sendDeadline = t
   269  	}
   270  	return err
   271  }
   272  
   273  // 读取全部缓冲区数据时,读取完毕后的写入等待间隔,如果超过该等待时间后仍无可读数据,那么读取操作返回。
   274  // 该时间间隔不能设置得太大,会影响Recv读取时长(默认为1毫秒)。
   275  func (c *Conn) SetRecvBufferWait(bufferWaitDuration time.Duration) {
   276  	c.recvBufferWait = bufferWaitDuration
   277  }