Skip to content

Commit cf74223

Browse files
authored
refactor(net/gudp): improve implements (#3491)
1 parent 1c97b7a commit cf74223

7 files changed

+205
-199
lines changed

net/gudp/gudp_conn.go

+14-121
Original file line numberDiff line numberDiff line change
@@ -14,85 +14,33 @@ import (
1414
"github.com/gogf/gf/v2/errors/gerror"
1515
)
1616

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.
17+
// localConn provides common operations for udp connection.
18+
type localConn struct {
19+
*net.UDPConn // Underlying UDP connection.
20+
deadlineRecv time.Time // Timeout point for reading data.
21+
deadlineSend time.Time // Timeout point for writing data.
2422
}
2523

2624
const (
2725
defaultRetryInterval = 100 * time.Millisecond // Retry interval.
2826
defaultReadBufferSize = 1024 // (Byte)Buffer size.
29-
receiveAllWaitTimeout = time.Millisecond // Default interval for reading buffer.
3027
)
3128

29+
// Retry holds the retry options.
30+
// TODO replace with standalone retry package.
3231
type Retry struct {
3332
Count int // Max retry count.
3433
Interval time.Duration // Retry interval.
3534
}
3635

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-
8836
// 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.
37+
// The parameter `buffer` is used for customizing the receiving buffer size.
38+
// If `buffer` <= 0, it uses the default buffer size, which is 1024 byte.
9139
//
9240
// There's package border in UDP protocol, we can receive a complete package if specified
9341
// buffer size is big enough. VERY NOTE that we should receive the complete package in once
9442
// or else the leftover package data would be dropped.
95-
func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
43+
func (c *localConn) Recv(buffer int, retry ...Retry) ([]byte, *net.UDPAddr, error) {
9644
var (
9745
err error // Reading error
9846
size int // Reading size
@@ -106,9 +54,6 @@ func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
10654
}
10755
for {
10856
size, remoteAddr, err = c.ReadFromUDP(data)
109-
if err == nil {
110-
c.remoteAddr = remoteAddr
111-
}
11257
if err != nil {
11358
// Connection closed.
11459
if err == io.EOF {
@@ -131,51 +76,11 @@ func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
13176
}
13277
break
13378
}
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...)
79+
return data[:size], remoteAddr, err
17580
}
17681

17782
// SetDeadline sets the read and write deadlines associated with the connection.
178-
func (c *Conn) SetDeadline(t time.Time) (err error) {
83+
func (c *localConn) SetDeadline(t time.Time) (err error) {
17984
if err = c.UDPConn.SetDeadline(t); err == nil {
18085
c.deadlineRecv = t
18186
c.deadlineSend = t
@@ -186,7 +91,7 @@ func (c *Conn) SetDeadline(t time.Time) (err error) {
18691
}
18792

18893
// SetDeadlineRecv sets the read deadline associated with the connection.
189-
func (c *Conn) SetDeadlineRecv(t time.Time) (err error) {
94+
func (c *localConn) SetDeadlineRecv(t time.Time) (err error) {
19095
if err = c.SetReadDeadline(t); err == nil {
19196
c.deadlineRecv = t
19297
} else {
@@ -196,23 +101,11 @@ func (c *Conn) SetDeadlineRecv(t time.Time) (err error) {
196101
}
197102

198103
// SetDeadlineSend sets the deadline of sending for current connection.
199-
func (c *Conn) SetDeadlineSend(t time.Time) (err error) {
104+
func (c *localConn) SetDeadlineSend(t time.Time) (err error) {
200105
if err = c.SetWriteDeadline(t); err == nil {
201106
c.deadlineSend = t
202107
} else {
203108
err = gerror.Wrapf(err, `SetDeadlineSend for connection failed with "%s"`, t)
204109
}
205110
return err
206111
}
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-
}

net/gudp/gudp_conn_client_conn.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
"time"
12+
13+
"github.com/gogf/gf/v2/errors/gerror"
14+
)
15+
16+
// ClientConn holds the client side connection.
17+
type ClientConn struct {
18+
*localConn
19+
}
20+
21+
// NewClientConn creates UDP connection to `remoteAddress`.
22+
// The optional parameter `localAddress` specifies the local address for connection.
23+
func NewClientConn(remoteAddress string, localAddress ...string) (*ClientConn, error) {
24+
udpConn, err := NewNetConn(remoteAddress, localAddress...)
25+
if err != nil {
26+
return nil, err
27+
}
28+
return &ClientConn{
29+
localConn: &localConn{
30+
UDPConn: udpConn,
31+
},
32+
}, nil
33+
}
34+
35+
// Send writes data to remote address.
36+
func (c *ClientConn) Send(data []byte, retry ...Retry) (err error) {
37+
for {
38+
_, err = c.Write(data)
39+
if err == nil {
40+
return nil
41+
}
42+
// Connection closed.
43+
if err == io.EOF {
44+
return err
45+
}
46+
// Still failed even after retrying.
47+
if len(retry) == 0 || retry[0].Count == 0 {
48+
return gerror.Wrap(err, `Write data failed`)
49+
}
50+
if len(retry) > 0 {
51+
retry[0].Count--
52+
if retry[0].Interval == 0 {
53+
retry[0].Interval = defaultRetryInterval
54+
}
55+
time.Sleep(retry[0].Interval)
56+
continue
57+
}
58+
return err
59+
}
60+
}
61+
62+
// SendRecv writes data to connection and blocks reading response.
63+
func (c *ClientConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
64+
if err := c.Send(data, retry...); err != nil {
65+
return nil, err
66+
}
67+
result, _, err := c.Recv(receive, retry...)
68+
return result, err
69+
}

net/gudp/gudp_conn_server_conn.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
// ServerConn holds the server side connection.
18+
type ServerConn struct {
19+
*localConn
20+
}
21+
22+
// NewServerConn creates an udp connection that listens to `localAddress`.
23+
func NewServerConn(listenedConn *net.UDPConn) *ServerConn {
24+
return &ServerConn{
25+
localConn: &localConn{
26+
UDPConn: listenedConn,
27+
},
28+
}
29+
}
30+
31+
// Send writes data to remote address.
32+
func (c *ServerConn) Send(data []byte, remoteAddr *net.UDPAddr, retry ...Retry) (err error) {
33+
for {
34+
_, err = c.WriteToUDP(data, remoteAddr)
35+
if err == nil {
36+
return nil
37+
}
38+
// Connection closed.
39+
if err == io.EOF {
40+
return err
41+
}
42+
// Still failed even after retrying.
43+
if len(retry) == 0 || retry[0].Count == 0 {
44+
return gerror.Wrap(err, `Write data failed`)
45+
}
46+
if len(retry) > 0 {
47+
retry[0].Count--
48+
if retry[0].Interval == 0 {
49+
retry[0].Interval = defaultRetryInterval
50+
}
51+
time.Sleep(retry[0].Interval)
52+
continue
53+
}
54+
return err
55+
}
56+
}

net/gudp/gudp_func.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func NewNetConn(remoteAddress string, localAddress ...string) (*net.UDPConn, err
5252
// Send writes data to `address` using UDP connection and then closes the connection.
5353
// Note that it is used for short connection usage.
5454
func Send(address string, data []byte, retry ...Retry) error {
55-
conn, err := NewConn(address)
55+
conn, err := NewClientConn(address)
5656
if err != nil {
5757
return err
5858
}
@@ -63,7 +63,7 @@ func Send(address string, data []byte, retry ...Retry) error {
6363
// SendRecv writes data to `address` using UDP connection, reads response and then closes the connection.
6464
// Note that it is used for short connection usage.
6565
func SendRecv(address string, data []byte, receive int, retry ...Retry) ([]byte, error) {
66-
conn, err := NewConn(address)
66+
conn, err := NewClientConn(address)
6767
if err != nil {
6868
return nil, err
6969
}
@@ -72,6 +72,8 @@ func SendRecv(address string, data []byte, receive int, retry ...Retry) ([]byte,
7272
}
7373

7474
// MustGetFreePort performs as GetFreePort, but it panics if any error occurs.
75+
// Deprecated: the port might be used soon after they were returned, please use `:0` as the listening
76+
// address which asks system to assign a free port instead.
7577
func MustGetFreePort() (port int) {
7678
port, err := GetFreePort()
7779
if err != nil {
@@ -81,6 +83,8 @@ func MustGetFreePort() (port int) {
8183
}
8284

8385
// GetFreePort retrieves and returns a port that is free.
86+
// Deprecated: the port might be used soon after they were returned, please use `:0` as the listening
87+
// address which asks system to assign a free port instead.
8488
func GetFreePort() (port int, err error) {
8589
var (
8690
network = `udp`
@@ -108,6 +112,8 @@ func GetFreePort() (port int, err error) {
108112
}
109113

110114
// GetFreePorts retrieves and returns specified number of ports that are free.
115+
// Deprecated: the ports might be used soon after they were returned, please use `:0` as the listening
116+
// address which asks system to assign a free port instead.
111117
func GetFreePorts(count int) (ports []int, err error) {
112118
var (
113119
network = `udp`

0 commit comments

Comments
 (0)