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 }