github.com/gogf/gf@v1.16.9/net/gudp/gudp_conn.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). 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/gogf/gf.
     6  
     7  package gudp
     8  
     9  import (
    10  	"io"
    11  	"net"
    12  	"time"
    13  )
    14  
    15  // Conn handles the UDP connection.
    16  type Conn struct {
    17  	*net.UDPConn                    // Underlying UDP connection.
    18  	remoteAddr        *net.UDPAddr  // Remote address.
    19  	receiveDeadline   time.Time     // Timeout point for reading data.
    20  	sendDeadline      time.Time     // Timeout point for writing data.
    21  	receiveBufferWait time.Duration // Interval duration for reading buffer.
    22  }
    23  
    24  const (
    25  	defaultRetryInterval  = 100 * time.Millisecond // Retry interval.
    26  	defaultReadBufferSize = 1024                   // (Byte)Buffer size.
    27  	receiveAllWaitTimeout = time.Millisecond       // Default interval for reading buffer.
    28  )
    29  
    30  type Retry struct {
    31  	Count    int           // Max retry count.
    32  	Interval time.Duration // Retry interval.
    33  }
    34  
    35  // NewConn creates UDP connection to <remoteAddress>.
    36  // The optional parameter <localAddress> specifies the local address for connection.
    37  func NewConn(remoteAddress string, localAddress ...string) (*Conn, error) {
    38  	if conn, err := NewNetConn(remoteAddress, localAddress...); err == nil {
    39  		return NewConnByNetConn(conn), nil
    40  	} else {
    41  		return nil, err
    42  	}
    43  }
    44  
    45  // NewConnByNetConn creates a UDP connection object with given *net.UDPConn object.
    46  func NewConnByNetConn(udp *net.UDPConn) *Conn {
    47  	return &Conn{
    48  		UDPConn:           udp,
    49  		receiveDeadline:   time.Time{},
    50  		sendDeadline:      time.Time{},
    51  		receiveBufferWait: receiveAllWaitTimeout,
    52  	}
    53  }
    54  
    55  // Send writes data to remote address.
    56  func (c *Conn) Send(data []byte, retry ...Retry) (err error) {
    57  	for {
    58  		if c.remoteAddr != nil {
    59  			_, err = c.WriteToUDP(data, c.remoteAddr)
    60  		} else {
    61  			_, err = c.Write(data)
    62  		}
    63  		if err != nil {
    64  			// Connection closed.
    65  			if err == io.EOF {
    66  				return err
    67  			}
    68  			// Still failed even after retrying.
    69  			if len(retry) == 0 || retry[0].Count == 0 {
    70  				return err
    71  			}
    72  			if len(retry) > 0 {
    73  				retry[0].Count--
    74  				if retry[0].Interval == 0 {
    75  					retry[0].Interval = defaultRetryInterval
    76  				}
    77  				time.Sleep(retry[0].Interval)
    78  			}
    79  		} else {
    80  			return nil
    81  		}
    82  	}
    83  }
    84  
    85  // Recv receives and returns data from remote address.
    86  // The parameter <buffer> is used for customizing the receiving buffer size. If <buffer> <= 0,
    87  // it uses the default buffer size, which is 1024 byte.
    88  //
    89  // There's package border in UDP protocol, we can receive a complete package if specified
    90  // buffer size is big enough. VERY NOTE that we should receive the complete package in once
    91  // or else the leftover package data would be dropped.
    92  func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
    93  	var err error               // Reading error.
    94  	var size int                // Reading size.
    95  	var data []byte             // Buffer object.
    96  	var remoteAddr *net.UDPAddr // Current remote address for reading.
    97  	if buffer > 0 {
    98  		data = make([]byte, buffer)
    99  	} else {
   100  		data = make([]byte, defaultReadBufferSize)
   101  	}
   102  	for {
   103  		size, remoteAddr, err = c.ReadFromUDP(data)
   104  		if err == nil {
   105  			c.remoteAddr = remoteAddr
   106  		}
   107  		if err != nil {
   108  			// Connection closed.
   109  			if err == io.EOF {
   110  				break
   111  			}
   112  			if len(retry) > 0 {
   113  				// It fails even it retried.
   114  				if retry[0].Count == 0 {
   115  					break
   116  				}
   117  				retry[0].Count--
   118  				if retry[0].Interval == 0 {
   119  					retry[0].Interval = defaultRetryInterval
   120  				}
   121  				time.Sleep(retry[0].Interval)
   122  				continue
   123  			}
   124  			break
   125  		}
   126  		break
   127  	}
   128  	return data[:size], err
   129  }
   130  
   131  // SendRecv writes data to connection and blocks reading response.
   132  func (c *Conn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
   133  	if err := c.Send(data, retry...); err == nil {
   134  		return c.Recv(receive, retry...)
   135  	} else {
   136  		return nil, err
   137  	}
   138  }
   139  
   140  // RecvWithTimeout reads data from remote address with timeout.
   141  func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
   142  	if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
   143  		return nil, err
   144  	}
   145  	defer c.SetRecvDeadline(time.Time{})
   146  	data, err = c.Recv(length, retry...)
   147  	return
   148  }
   149  
   150  // SendWithTimeout writes data to connection with timeout.
   151  func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
   152  	if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
   153  		return err
   154  	}
   155  	defer c.SetSendDeadline(time.Time{})
   156  	err = c.Send(data, retry...)
   157  	return
   158  }
   159  
   160  // SendRecvWithTimeout writes data to connection and reads response with timeout.
   161  func (c *Conn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
   162  	if err := c.Send(data, retry...); err == nil {
   163  		return c.RecvWithTimeout(receive, timeout, retry...)
   164  	} else {
   165  		return nil, err
   166  	}
   167  }
   168  
   169  func (c *Conn) SetDeadline(t time.Time) error {
   170  	err := c.UDPConn.SetDeadline(t)
   171  	if err == nil {
   172  		c.receiveDeadline = t
   173  		c.sendDeadline = t
   174  	}
   175  	return err
   176  }
   177  
   178  func (c *Conn) SetRecvDeadline(t time.Time) error {
   179  	err := c.SetReadDeadline(t)
   180  	if err == nil {
   181  		c.receiveDeadline = t
   182  	}
   183  	return err
   184  }
   185  
   186  func (c *Conn) SetSendDeadline(t time.Time) error {
   187  	err := c.SetWriteDeadline(t)
   188  	if err == nil {
   189  		c.sendDeadline = t
   190  	}
   191  	return err
   192  }
   193  
   194  // SetRecvBufferWait sets the buffer waiting timeout when reading all data from connection.
   195  // The waiting duration cannot be too long which might delay receiving data from remote address.
   196  func (c *Conn) SetRecvBufferWait(d time.Duration) {
   197  	c.receiveBufferWait = d
   198  }
   199  
   200  // RemoteAddr returns the remote address of current UDP connection.
   201  // Note that it cannot use c.conn.RemoteAddr() as it's nil.
   202  func (c *Conn) RemoteAddr() net.Addr {
   203  	//return c.conn.RemoteAddr()
   204  	return c.remoteAddr
   205  }