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 }