gudp_conn.go 6.2 KB

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