2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2018-07-18 11:43:30 +08:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-07-18 11:43:30 +08:00
|
|
|
|
|
|
|
package gtcp
|
|
|
|
|
|
|
|
import (
|
2019-06-04 23:33:46 +08:00
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"crypto/tls"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"time"
|
2021-12-22 22:22:42 +08:00
|
|
|
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
2018-07-18 11:43:30 +08:00
|
|
|
)
|
|
|
|
|
2021-08-08 13:10:21 +08:00
|
|
|
// Conn is the TCP connection object.
|
2018-07-18 11:43:30 +08:00
|
|
|
type Conn struct {
|
2021-08-08 13:10:21 +08:00
|
|
|
net.Conn // Underlying TCP connection object.
|
|
|
|
reader *bufio.Reader // Buffer reader for connection.
|
|
|
|
receiveDeadline time.Time // Timeout point for reading.
|
|
|
|
sendDeadline time.Time // Timeout point for writing.
|
|
|
|
receiveBufferWait time.Duration // Interval duration for reading buffer.
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 12:32:03 +08:00
|
|
|
const (
|
2019-10-01 17:53:49 +08:00
|
|
|
// Default interval for reading buffer.
|
2021-08-08 13:10:21 +08:00
|
|
|
receiveAllWaitTimeout = time.Millisecond
|
2018-07-21 12:32:03 +08:00
|
|
|
)
|
|
|
|
|
2019-10-01 17:53:49 +08:00
|
|
|
// NewConn creates and returns a new connection with given address.
|
2019-10-30 19:55:50 +08:00
|
|
|
func NewConn(addr string, timeout ...time.Duration) (*Conn, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if conn, err := NewNetConn(addr, timeout...); err == nil {
|
|
|
|
return NewConnByNetConn(conn), nil
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 17:53:49 +08:00
|
|
|
// NewConnTLS creates and returns a new TLS connection
|
|
|
|
// with given address and TLS configuration.
|
2019-06-04 23:33:46 +08:00
|
|
|
func NewConnTLS(addr string, tlsConfig *tls.Config) (*Conn, error) {
|
|
|
|
if conn, err := NewNetConnTLS(addr, tlsConfig); err == nil {
|
|
|
|
return NewConnByNetConn(conn), nil
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 17:53:49 +08:00
|
|
|
// NewConnKeyCrt creates and returns a new TLS connection
|
|
|
|
// with given address and TLS certificate and key files.
|
2019-06-04 23:33:46 +08:00
|
|
|
func NewConnKeyCrt(addr, crtFile, keyFile string) (*Conn, error) {
|
|
|
|
if conn, err := NewNetConnKeyCrt(addr, crtFile, keyFile); err == nil {
|
|
|
|
return NewConnByNetConn(conn), nil
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 17:53:49 +08:00
|
|
|
// NewConnByNetConn creates and returns a TCP connection object with given net.Conn object.
|
2018-07-18 11:43:30 +08:00
|
|
|
func NewConnByNetConn(conn net.Conn) *Conn {
|
2019-06-19 09:06:52 +08:00
|
|
|
return &Conn{
|
2021-08-08 13:10:21 +08:00
|
|
|
Conn: conn,
|
|
|
|
reader: bufio.NewReader(conn),
|
|
|
|
receiveDeadline: time.Time{},
|
|
|
|
sendDeadline: time.Time{},
|
|
|
|
receiveBufferWait: receiveAllWaitTimeout,
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 17:53:49 +08:00
|
|
|
// Send writes data to remote address.
|
2019-06-19 09:06:52 +08:00
|
|
|
func (c *Conn) Send(data []byte, retry ...Retry) error {
|
|
|
|
for {
|
2019-06-21 22:23:07 +08:00
|
|
|
if _, err := c.Write(data); err != nil {
|
2019-10-01 17:53:49 +08:00
|
|
|
// Connection closed.
|
2019-06-19 09:06:52 +08:00
|
|
|
if err == io.EOF {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-01 17:53:49 +08:00
|
|
|
// Still failed even after retrying.
|
2019-06-19 09:06:52 +08:00
|
|
|
if len(retry) == 0 || retry[0].Count == 0 {
|
2021-12-22 22:22:42 +08:00
|
|
|
err = gerror.Wrap(err, `Write data failed`)
|
2019-06-19 09:06:52 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(retry) > 0 {
|
|
|
|
retry[0].Count--
|
|
|
|
if retry[0].Interval == 0 {
|
2021-08-08 13:10:21 +08:00
|
|
|
retry[0].Interval = defaultRetryInternal
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-12-11 14:54:38 +08:00
|
|
|
time.Sleep(retry[0].Interval)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2020-03-11 23:59:43 +08:00
|
|
|
// Recv receives and returns data from the connection.
|
2019-06-03 23:53:59 +08:00
|
|
|
//
|
2019-10-01 17:53:49 +08:00
|
|
|
// Note that,
|
2019-12-11 14:54:38 +08:00
|
|
|
// 1. If length = 0, which means it receives the data from current buffer and returns immediately.
|
2020-06-15 22:51:44 +08:00
|
|
|
// 2. If length < 0, which means it receives all data from connection and returns it until no data
|
|
|
|
// from connection. Developers should notice the package parsing yourself if you decide receiving
|
|
|
|
// all data from buffer.
|
2019-12-11 14:54:38 +08:00
|
|
|
// 3. If length > 0, which means it blocks reading data from connection until length size was received.
|
|
|
|
// It is the most commonly used length value for data receiving.
|
2019-06-19 09:06:52 +08:00
|
|
|
func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {
|
2021-12-22 22:22:42 +08:00
|
|
|
var (
|
|
|
|
err error // Reading error.
|
|
|
|
size int // Reading size.
|
|
|
|
index int // Received size.
|
|
|
|
buffer []byte // Buffer object.
|
|
|
|
bufferWait bool // Whether buffer reading timeout set.
|
|
|
|
)
|
2019-06-19 09:06:52 +08:00
|
|
|
if length > 0 {
|
|
|
|
buffer = make([]byte, length)
|
|
|
|
} else {
|
2021-08-08 13:10:21 +08:00
|
|
|
buffer = make([]byte, defaultReadBufferSize)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-07-20 18:14:21 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
for {
|
|
|
|
if length < 0 && index > 0 {
|
|
|
|
bufferWait = true
|
2021-08-08 13:10:21 +08:00
|
|
|
if err = c.SetReadDeadline(time.Now().Add(c.receiveBufferWait)); err != nil {
|
2021-12-22 22:22:42 +08:00
|
|
|
err = gerror.Wrap(err, `SetReadDeadline for connection failed`)
|
2019-06-19 09:06:52 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
size, err = c.reader.Read(buffer[index:])
|
|
|
|
if size > 0 {
|
|
|
|
index += size
|
|
|
|
if length > 0 {
|
2021-10-21 18:22:47 +08:00
|
|
|
// It reads til `length` size if `length` is specified.
|
2019-06-19 09:06:52 +08:00
|
|
|
if index == length {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
} else {
|
2021-08-08 13:10:21 +08:00
|
|
|
if index >= defaultReadBufferSize {
|
2019-10-01 17:53:49 +08:00
|
|
|
// If it exceeds the buffer size, it then automatically increases its buffer size.
|
2021-08-08 13:10:21 +08:00
|
|
|
buffer = append(buffer, make([]byte, defaultReadBufferSize)...)
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2019-10-01 17:53:49 +08:00
|
|
|
// It returns immediately if received size is lesser than buffer size.
|
2019-06-19 09:06:52 +08:00
|
|
|
if !bufferWait {
|
2019-04-29 23:54:47 +08:00
|
|
|
break
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
2019-10-01 17:53:49 +08:00
|
|
|
// Connection closed.
|
2019-06-19 09:06:52 +08:00
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
2019-10-01 17:53:49 +08:00
|
|
|
// Re-set the timeout when reading data.
|
2019-06-19 09:06:52 +08:00
|
|
|
if bufferWait && isTimeout(err) {
|
2021-08-08 13:10:21 +08:00
|
|
|
if err = c.SetReadDeadline(c.receiveDeadline); err != nil {
|
2021-12-22 22:22:42 +08:00
|
|
|
err = gerror.Wrap(err, `SetReadDeadline for connection failed`)
|
2019-06-19 09:06:52 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = nil
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if len(retry) > 0 {
|
2019-10-01 17:53:49 +08:00
|
|
|
// It fails even it retried.
|
2019-06-19 09:06:52 +08:00
|
|
|
if retry[0].Count == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
retry[0].Count--
|
|
|
|
if retry[0].Interval == 0 {
|
2021-08-08 13:10:21 +08:00
|
|
|
retry[0].Interval = defaultRetryInternal
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-12-11 14:54:38 +08:00
|
|
|
time.Sleep(retry[0].Interval)
|
2019-06-19 09:06:52 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
2019-10-01 17:53:49 +08:00
|
|
|
// Just read once from buffer.
|
2019-06-19 09:06:52 +08:00
|
|
|
if length == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buffer[:index], err
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2019-10-30 19:55:50 +08:00
|
|
|
// RecvLine reads data from the connection until reads char '\n'.
|
|
|
|
// Note that the returned result does not contain the last char '\n'.
|
2019-06-19 09:06:52 +08:00
|
|
|
func (c *Conn) RecvLine(retry ...Retry) ([]byte, error) {
|
2021-12-22 22:22:42 +08:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
buffer []byte
|
|
|
|
data = make([]byte, 0)
|
|
|
|
)
|
2019-06-19 09:06:52 +08:00
|
|
|
for {
|
|
|
|
buffer, err = c.Recv(1, retry...)
|
|
|
|
if len(buffer) > 0 {
|
|
|
|
if buffer[0] == '\n' {
|
2019-11-14 15:41:28 +08:00
|
|
|
data = append(data, buffer[:len(buffer)-1]...)
|
2019-06-19 09:06:52 +08:00
|
|
|
break
|
2019-11-14 15:41:28 +08:00
|
|
|
} else {
|
|
|
|
data = append(data, buffer...)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2019-11-14 15:41:28 +08:00
|
|
|
return data, err
|
|
|
|
}
|
|
|
|
|
2021-12-22 22:22:42 +08:00
|
|
|
// RecvTill reads data from the connection until reads bytes `til`.
|
2021-10-21 18:22:47 +08:00
|
|
|
// Note that the returned result contains the last bytes `til`.
|
2021-12-22 22:22:42 +08:00
|
|
|
func (c *Conn) RecvTill(til []byte, retry ...Retry) ([]byte, error) {
|
|
|
|
var (
|
|
|
|
err error
|
|
|
|
buffer []byte
|
|
|
|
data = make([]byte, 0)
|
|
|
|
length = len(til)
|
|
|
|
)
|
2019-11-14 15:41:28 +08:00
|
|
|
for {
|
|
|
|
buffer, err = c.Recv(1, retry...)
|
|
|
|
if len(buffer) > 0 {
|
|
|
|
if length > 0 &&
|
|
|
|
len(data) >= length-1 &&
|
|
|
|
buffer[0] == til[length-1] &&
|
|
|
|
bytes.EqualFold(data[len(data)-length+1:], til[:length-1]) {
|
|
|
|
data = append(data, buffer...)
|
|
|
|
break
|
|
|
|
} else {
|
|
|
|
data = append(data, buffer...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
return data, err
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|
|
|
|
|
2019-10-30 19:55:50 +08:00
|
|
|
// RecvWithTimeout reads data from the connection with timeout.
|
2019-06-21 22:23:07 +08:00
|
|
|
func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
|
2021-12-22 22:22:42 +08:00
|
|
|
if err = c.SetReceiveDeadline(time.Now().Add(timeout)); err != nil {
|
2019-06-19 09:06:52 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-12-22 22:22:42 +08:00
|
|
|
defer c.SetReceiveDeadline(time.Time{})
|
2019-06-21 22:23:07 +08:00
|
|
|
data, err = c.Recv(length, retry...)
|
|
|
|
return
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2019-10-30 19:55:50 +08:00
|
|
|
// SendWithTimeout writes data to the connection with timeout.
|
2019-06-21 22:23:07 +08:00
|
|
|
func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
|
2021-12-22 22:22:42 +08:00
|
|
|
if err = c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
|
2019-06-04 18:26:32 +08:00
|
|
|
return err
|
|
|
|
}
|
2019-10-11 22:54:25 +08:00
|
|
|
defer c.SetSendDeadline(time.Time{})
|
2019-06-21 22:23:07 +08:00
|
|
|
err = c.Send(data, retry...)
|
|
|
|
return
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2019-10-30 19:55:50 +08:00
|
|
|
// SendRecv writes data to the connection and blocks reading response.
|
|
|
|
func (c *Conn) SendRecv(data []byte, length int, retry ...Retry) ([]byte, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if err := c.Send(data, retry...); err == nil {
|
2019-10-30 19:55:50 +08:00
|
|
|
return c.Recv(length, retry...)
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-18 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
2019-10-30 19:55:50 +08:00
|
|
|
// SendRecvWithTimeout writes data to the connection and reads response with timeout.
|
|
|
|
func (c *Conn) SendRecvWithTimeout(data []byte, length int, timeout time.Duration, retry ...Retry) ([]byte, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if err := c.Send(data, retry...); err == nil {
|
2019-10-30 19:55:50 +08:00
|
|
|
return c.RecvWithTimeout(length, timeout, retry...)
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|
|
|
|
|
2021-12-22 22:22:42 +08:00
|
|
|
func (c *Conn) SetDeadline(t time.Time) (err error) {
|
|
|
|
if err = c.Conn.SetDeadline(t); err == nil {
|
2021-08-08 13:10:21 +08:00
|
|
|
c.receiveDeadline = t
|
2019-06-19 09:06:52 +08:00
|
|
|
c.sendDeadline = t
|
|
|
|
}
|
2021-12-22 22:22:42 +08:00
|
|
|
if err != nil {
|
|
|
|
err = gerror.Wrapf(err, `SetDeadline for connection failed with "%s"`, t)
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
return err
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|
|
|
|
|
2021-12-22 22:22:42 +08:00
|
|
|
func (c *Conn) SetReceiveDeadline(t time.Time) (err error) {
|
|
|
|
if err = c.SetReadDeadline(t); err == nil {
|
2021-08-08 13:10:21 +08:00
|
|
|
c.receiveDeadline = t
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-12-22 22:22:42 +08:00
|
|
|
if err != nil {
|
|
|
|
err = gerror.Wrapf(err, `SetReadDeadline for connection failed with "%s"`, t)
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
return err
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|
|
|
|
|
2021-12-22 22:22:42 +08:00
|
|
|
func (c *Conn) SetSendDeadline(t time.Time) (err error) {
|
|
|
|
if err = c.SetWriteDeadline(t); err == nil {
|
2019-06-19 09:06:52 +08:00
|
|
|
c.sendDeadline = t
|
|
|
|
}
|
2021-12-22 22:22:42 +08:00
|
|
|
if err != nil {
|
|
|
|
err = gerror.Wrapf(err, `SetWriteDeadline for connection failed with "%s"`, t)
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
return err
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|
|
|
|
|
2021-12-22 22:22:42 +08:00
|
|
|
// SetReceiveBufferWait sets the buffer waiting timeout when reading all data from connection.
|
2019-10-01 17:53:49 +08:00
|
|
|
// The waiting duration cannot be too long which might delay receiving data from remote address.
|
2021-12-22 22:22:42 +08:00
|
|
|
func (c *Conn) SetReceiveBufferWait(bufferWaitDuration time.Duration) {
|
2021-08-08 13:10:21 +08:00
|
|
|
c.receiveBufferWait = bufferWaitDuration
|
2018-07-21 12:32:03 +08:00
|
|
|
}
|