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