github.com/zhongdalu/gf@v1.0.0/g/net/gtcp/gtcp_pool.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  	"time"
    11  
    12  	"github.com/zhongdalu/gf/g/container/gmap"
    13  	"github.com/zhongdalu/gf/g/container/gpool"
    14  	"github.com/zhongdalu/gf/g/errors/gerror"
    15  )
    16  
    17  // 链接池链接对象
    18  type PoolConn struct {
    19  	*Conn              // 继承底层链接接口对象
    20  	pool   *gpool.Pool // 对应的链接池对象
    21  	status int         // 当前对象的状态,主要用于失败重连判断
    22  }
    23  
    24  const (
    25  	gDEFAULT_POOL_EXPIRE = 60000 // (毫秒)默认链接对象过期时间
    26  	gCONN_STATUS_UNKNOWN = 0     // 未知,表示未经过连通性操作;
    27  	gCONN_STATUS_ACTIVE  = 1     // 正常,表示已经经过连通性操作
    28  	gCONN_STATUS_ERROR   = 2     // 错误,表示该接口操作产生了错误,不应当被循环使用了
    29  
    30  )
    31  
    32  var (
    33  	// 连接池对象map,键名为地址端口,键值为对应的连接池对象
    34  	pools = gmap.NewStrAnyMap()
    35  )
    36  
    37  // 创建TCP链接池对象
    38  func NewPoolConn(addr string, timeout ...int) (*PoolConn, error) {
    39  	var pool *gpool.Pool
    40  	if v := pools.Get(addr); v == nil {
    41  		pools.LockFunc(func(m map[string]interface{}) {
    42  			if v, ok := m[addr]; ok {
    43  				pool = v.(*gpool.Pool)
    44  			} else {
    45  				pool = gpool.New(gDEFAULT_POOL_EXPIRE, func() (interface{}, error) {
    46  					if conn, err := NewConn(addr, timeout...); err == nil {
    47  						return &PoolConn{conn, pool, gCONN_STATUS_ACTIVE}, nil
    48  					} else {
    49  						return nil, err
    50  					}
    51  				})
    52  				m[addr] = pool
    53  			}
    54  		})
    55  	} else {
    56  		pool = v.(*gpool.Pool)
    57  	}
    58  
    59  	if v, err := pool.Get(); err == nil {
    60  		return v.(*PoolConn), nil
    61  	} else {
    62  		return nil, err
    63  	}
    64  }
    65  
    66  // (方法覆盖)覆盖底层接口对象的Close方法
    67  func (c *PoolConn) Close() error {
    68  	if c.pool != nil && c.status == gCONN_STATUS_ACTIVE {
    69  		c.status = gCONN_STATUS_UNKNOWN
    70  		c.pool.Put(c)
    71  	} else {
    72  		return c.Conn.Close()
    73  	}
    74  	return nil
    75  }
    76  
    77  // (方法覆盖)发送数据
    78  func (c *PoolConn) Send(data []byte, retry ...Retry) error {
    79  	var err error
    80  	if err = c.Conn.Send(data, retry...); err != nil && c.status == gCONN_STATUS_UNKNOWN {
    81  		if v, e := c.pool.NewFunc(); e == nil {
    82  			c.Conn = v.(*PoolConn).Conn
    83  			err = c.Conn.Send(data, retry...)
    84  		} else {
    85  			err = e
    86  		}
    87  	}
    88  	if err != nil {
    89  		c.status = gCONN_STATUS_ERROR
    90  	} else {
    91  		c.status = gCONN_STATUS_ACTIVE
    92  	}
    93  	return err
    94  }
    95  
    96  // (方法覆盖)接收数据
    97  func (c *PoolConn) Recv(length int, retry ...Retry) ([]byte, error) {
    98  	data, err := c.Conn.Recv(length, retry...)
    99  	if err != nil {
   100  		c.status = gCONN_STATUS_ERROR
   101  	} else {
   102  		c.status = gCONN_STATUS_ACTIVE
   103  	}
   104  	return data, err
   105  }
   106  
   107  // (方法覆盖)按行读取数据,阻塞读取,直到完成一行读取位置(末尾以'\n'结尾,返回数据不包含换行符)
   108  func (c *PoolConn) RecvLine(retry ...Retry) ([]byte, error) {
   109  	data, err := c.Conn.RecvLine(retry...)
   110  	if err != nil {
   111  		c.status = gCONN_STATUS_ERROR
   112  	} else {
   113  		c.status = gCONN_STATUS_ACTIVE
   114  	}
   115  	return data, err
   116  }
   117  
   118  // (方法覆盖)带超时时间的数据获取
   119  func (c *PoolConn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
   120  	if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
   121  		return nil, err
   122  	}
   123  	defer func() {
   124  		err = gerror.Wrap(c.SetRecvDeadline(time.Time{}), "SetRecvDeadline error")
   125  	}()
   126  	data, err = c.Recv(length, retry...)
   127  	return
   128  }
   129  
   130  // (方法覆盖)带超时时间的数据发送
   131  func (c *PoolConn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
   132  	if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
   133  		return err
   134  	}
   135  	defer func() {
   136  		err = gerror.Wrap(c.SetSendDeadline(time.Time{}), "SetSendDeadline error")
   137  	}()
   138  	err = c.Send(data, retry...)
   139  	return
   140  }
   141  
   142  // (方法覆盖)发送数据并等待接收返回数据
   143  func (c *PoolConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
   144  	if err := c.Send(data, retry...); err == nil {
   145  		return c.Recv(receive, retry...)
   146  	} else {
   147  		return nil, err
   148  	}
   149  }
   150  
   151  // (方法覆盖)发送数据并等待接收返回数据(带返回超时等待时间)
   152  func (c *PoolConn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
   153  	if err := c.Send(data, retry...); err == nil {
   154  		return c.RecvWithTimeout(receive, timeout, retry...)
   155  	} else {
   156  		return nil, err
   157  	}
   158  }