gf/net/gtcp/gtcp_conn.go

278 lines
7.4 KiB
Go
Raw Normal View History

// Copyright 2018 gf Author(https://github.com/gogf/gf). 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,
// 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"
2019-06-22 22:05:39 +08:00
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/errors/gerror"
2018-07-18 11:43:30 +08:00
)
2019-10-01 17:53:49 +08:00
// TCP connection object.
2018-07-18 11:43:30 +08:00
type Conn struct {
2019-10-01 17:53:49 +08:00
net.Conn // Underlying TCP connection object.
reader *bufio.Reader // Buffer reader for connection.
buffer []byte // Buffer object.
recvDeadline time.Time // Timeout point for reading.
sendDeadline time.Time // Timeout point for writing.
recvBufferWait time.Duration // Interval duration for reading buffer.
2018-07-18 11:43:30 +08:00
}
const (
2019-10-01 17:53:49 +08:00
// Default interval for reading buffer.
2019-06-19 09:06:52 +08:00
gRECV_ALL_WAIT_TIMEOUT = time.Millisecond
)
2019-10-01 17:53:49 +08:00
// NewConn creates and returns a new connection with given address.
2019-06-19 09:06:52 +08:00
func NewConn(addr string, timeout ...int) (*Conn, error) {
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{
2019-06-21 22:23:07 +08:00
Conn: conn,
2019-06-19 09:06:52 +08:00
reader: bufio.NewReader(conn),
recvDeadline: time.Time{},
sendDeadline: time.Time{},
recvBufferWait: gRECV_ALL_WAIT_TIMEOUT,
}
}
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 {
return err
}
if len(retry) > 0 {
retry[0].Count--
if retry[0].Interval == 0 {
retry[0].Interval = gDEFAULT_RETRY_INTERVAL
}
time.Sleep(time.Duration(retry[0].Interval) * time.Millisecond)
}
} else {
return nil
}
}
2018-07-18 11:43:30 +08:00
}
2019-10-01 17:53:49 +08:00
// Recv receives data from remote address.
2019-06-03 23:53:59 +08:00
//
2019-10-01 17:53:49 +08:00
// Note that,
// 1. If length = 0, it means it receives the data from current buffer and returns immediately.
// 2. If length < 0, it means it receives all data from buffer and returns if it waits til no data from connection.
// Developers should notice the package parsing yourself if you decide receiving all data from buffer.
// 3. If length > 0, it means it blocks reading data from connection until length size was received.
2019-06-19 09:06:52 +08:00
func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {
2019-10-01 17:53:49 +08:00
var err error // Reading error.
var size int // Reading size.
var index int // Received size.
var buffer []byte // Buffer object.
var bufferWait bool // Whether buffer reading timeout set.
2019-06-19 09:06:52 +08:00
if length > 0 {
buffer = make([]byte, length)
} else {
buffer = make([]byte, gDEFAULT_READ_BUFFER_SIZE)
}
2018-07-20 18:14:21 +08:00
2019-06-19 09:06:52 +08:00
for {
if length < 0 && index > 0 {
bufferWait = true
2019-06-21 22:23:07 +08:00
if err = c.SetReadDeadline(time.Now().Add(c.recvBufferWait)); err != nil {
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 {
2019-10-01 17:53:49 +08:00
// It reads til <length> size if <length> is specified.
2019-06-19 09:06:52 +08:00
if index == length {
break
}
} else {
if index >= gDEFAULT_READ_BUFFER_SIZE {
2019-10-01 17:53:49 +08:00
// If it exceeds the buffer size, it then automatically increases its buffer size.
2019-06-19 09:06:52 +08:00
buffer = append(buffer, make([]byte, gDEFAULT_READ_BUFFER_SIZE)...)
} 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 {
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) {
2019-06-21 22:23:07 +08:00
if err = c.SetReadDeadline(c.recvDeadline); err != nil {
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 {
retry[0].Interval = gDEFAULT_RETRY_INTERVAL
}
time.Sleep(time.Duration(retry[0].Interval) * time.Millisecond)
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-01 17:53:49 +08:00
// RecvLine reads data from connection until reads char '\n'.
// Note that the returned result does not contain char '\n'.
2019-06-19 09:06:52 +08:00
func (c *Conn) RecvLine(retry ...Retry) ([]byte, error) {
var err error
var buffer []byte
data := make([]byte, 0)
for {
buffer, err = c.Recv(1, retry...)
if len(buffer) > 0 {
data = append(data, buffer...)
if buffer[0] == '\n' {
break
}
}
if err != nil {
break
}
}
if len(data) > 0 {
data = bytes.TrimRight(data, "\n\r")
}
return data, err
}
2019-10-01 17:53:49 +08:00
// RecvWithTimeout reads data from 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) {
2019-06-19 09:06:52 +08:00
if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
return nil, err
}
2019-06-21 22:23:07 +08:00
defer func() {
2019-06-29 23:35:32 +08:00
err = gerror.Wrap(c.SetRecvDeadline(time.Time{}), "SetRecvDeadline error")
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-01 17:53:49 +08:00
// SendWithTimeout writes data to connection with timeout.
2019-06-21 22:23:07 +08:00
func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
2019-06-04 18:26:32 +08:00
if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
return err
}
2019-06-21 22:23:07 +08:00
defer func() {
2019-06-29 23:35:32 +08:00
err = gerror.Wrap(c.SetSendDeadline(time.Time{}), "SetSendDeadline error")
2019-06-21 22:23:07 +08:00
}()
err = c.Send(data, retry...)
return
2018-07-18 11:43:30 +08:00
}
2019-10-01 17:53:49 +08:00
// SendRecv writes data to connection and blocks reading response.
2019-06-19 09:06:52 +08:00
func (c *Conn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
if err := c.Send(data, retry...); err == nil {
return c.Recv(receive, retry...)
} else {
return nil, err
}
2018-07-18 11:43:30 +08:00
}
2019-10-01 17:53:49 +08:00
// SendRecvWithTimeout writes data to connection and reads response with timeout.
2019-06-19 09:06:52 +08:00
func (c *Conn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
if err := c.Send(data, retry...); err == nil {
return c.RecvWithTimeout(receive, timeout, retry...)
} else {
return nil, err
}
}
func (c *Conn) SetDeadline(t time.Time) error {
2019-06-21 22:23:07 +08:00
err := c.Conn.SetDeadline(t)
2019-06-19 09:06:52 +08:00
if err == nil {
c.recvDeadline = t
c.sendDeadline = t
}
return err
}
func (c *Conn) SetRecvDeadline(t time.Time) error {
2019-06-21 22:23:07 +08:00
err := c.SetReadDeadline(t)
2019-06-19 09:06:52 +08:00
if err == nil {
c.recvDeadline = t
}
return err
}
func (c *Conn) SetSendDeadline(t time.Time) error {
2019-06-21 22:23:07 +08:00
err := c.SetWriteDeadline(t)
2019-06-19 09:06:52 +08:00
if err == nil {
c.sendDeadline = t
}
return err
}
2019-10-01 17:53:49 +08:00
// SetRecvBufferWait sets the buffer waiting timeout when reading all data from connection.
// The waiting duration cannot be too long which might delay receiving data from remote address.
2019-04-28 23:55:23 +08:00
func (c *Conn) SetRecvBufferWait(bufferWaitDuration time.Duration) {
2019-06-19 09:06:52 +08:00
c.recvBufferWait = bufferWaitDuration
}