gf/net/gudp/gudp_conn.go

206 lines
5.7 KiB
Go
Raw Normal View History

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,
// You can obtain one at https://github.com/gogf/gf.
2018-07-18 11:43:30 +08:00
package gudp
import (
2019-06-19 09:06:52 +08:00
"io"
"net"
"time"
2018-07-18 11:43:30 +08:00
)
2019-10-01 17:53:49 +08:00
// Conn handles the UDP connection.
2018-07-18 11:43:30 +08:00
type Conn struct {
*net.UDPConn // Underlying UDP connection.
remoteAddr *net.UDPAddr // Remote address.
receiveDeadline time.Time // Timeout point for reading data.
sendDeadline time.Time // Timeout point for writing data.
receiveBufferWait time.Duration // Interval duration for reading buffer.
2018-07-18 11:43:30 +08:00
}
const (
defaultRetryInterval = 100 * time.Millisecond // Retry interval.
defaultReadBufferSize = 1024 // (Byte)Buffer size.
receiveAllWaitTimeout = time.Millisecond // Default interval for reading buffer.
2018-07-18 11:43:30 +08:00
)
type Retry struct {
2019-10-01 17:53:49 +08:00
Count int // Max retry count.
Interval time.Duration // Retry interval.
2018-07-18 11:43:30 +08:00
}
2019-10-01 17:53:49 +08:00
// NewConn creates UDP connection to <remoteAddress>.
// The optional parameter <localAddress> specifies the local address for connection.
func NewConn(remoteAddress string, localAddress ...string) (*Conn, error) {
if conn, err := NewNetConn(remoteAddress, localAddress...); err == nil {
2019-06-19 09:06:52 +08:00
return NewConnByNetConn(conn), nil
} else {
return nil, err
}
2018-07-18 11:43:30 +08:00
}
2019-10-01 17:53:49 +08:00
// NewConnByNetConn creates a UDP connection object with given *net.UDPConn object.
2018-07-18 11:43:30 +08:00
func NewConnByNetConn(udp *net.UDPConn) *Conn {
2019-06-19 09:06:52 +08:00
return &Conn{
UDPConn: udp,
receiveDeadline: time.Time{},
sendDeadline: time.Time{},
receiveBufferWait: receiveAllWaitTimeout,
2019-06-19 09:06:52 +08:00
}
2018-07-18 11:43:30 +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) (err error) {
for {
2019-10-01 17:53:49 +08:00
if c.remoteAddr != nil {
_, err = c.WriteToUDP(data, c.remoteAddr)
2019-06-19 09:06:52 +08:00
} else {
2019-06-21 22:23:07 +08:00
_, err = c.Write(data)
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 {
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 = defaultRetryInterval
2019-06-19 09:06:52 +08:00
}
2019-10-01 17:53:49 +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 remote address.
2020-03-11 23:56:58 +08:00
// The parameter <buffer> is used for customizing the receiving buffer size. If <buffer> <= 0,
// it uses the default buffer size, which is 1024 byte.
2019-06-03 23:53:59 +08:00
//
2020-03-11 23:54:35 +08:00
// There's package border in UDP protocol, we can receive a complete package if specified
// buffer size is big enough. VERY NOTE that we should receive the complete package in once
// or else the leftover package data would be dropped.
func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
2019-10-01 17:53:49 +08:00
var err error // Reading error.
var size int // Reading size.
2020-03-11 23:54:35 +08:00
var data []byte // Buffer object.
2019-10-01 17:53:49 +08:00
var remoteAddr *net.UDPAddr // Current remote address for reading.
2020-03-11 23:54:35 +08:00
if buffer > 0 {
data = make([]byte, buffer)
2019-06-19 09:06:52 +08:00
} else {
data = make([]byte, defaultReadBufferSize)
2019-06-19 09:06:52 +08:00
}
for {
2020-03-11 23:54:35 +08:00
size, remoteAddr, err = c.ReadFromUDP(data)
2019-06-19 09:06:52 +08:00
if err == nil {
2019-10-01 17:53:49 +08:00
c.remoteAddr = remoteAddr
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
}
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 = defaultRetryInterval
2019-06-19 09:06:52 +08:00
}
time.Sleep(retry[0].Interval)
2019-06-19 09:06:52 +08:00
continue
}
break
}
2020-03-11 23:54:35 +08:00
break
2019-06-19 09:06:52 +08:00
}
2020-03-11 23:54:35 +08:00
return data[:size], err
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
}
}
2019-10-01 17:53:49 +08:00
// RecvWithTimeout reads data from remote address 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
}
defer c.SetRecvDeadline(time.Time{})
2019-06-21 22:23:07 +08:00
data, err = c.Recv(length, retry...)
return
}
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
}
defer c.SetSendDeadline(time.Time{})
2019-06-21 22:23:07 +08:00
err = c.Send(data, retry...)
return
}
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.UDPConn.SetDeadline(t)
2019-06-19 09:06:52 +08:00
if err == nil {
c.receiveDeadline = t
2019-06-19 09:06:52 +08:00
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.receiveDeadline = t
2019-06-19 09:06:52 +08:00
}
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.
func (c *Conn) SetRecvBufferWait(d time.Duration) {
c.receiveBufferWait = d
}
2019-10-01 17:53:49 +08:00
// RemoteAddr returns the remote address of current UDP connection.
// Note that it cannot use c.conn.RemoteAddr() as it's nil.
func (c *Conn) RemoteAddr() net.Addr {
2019-06-19 09:06:52 +08:00
//return c.conn.RemoteAddr()
2019-10-01 17:53:49 +08:00
return c.remoteAddr
}