mirror of
https://gitee.com/johng/gf
synced 2026-07-07 06:15:15 +08:00
improve package gudp
This commit is contained in:
@ -23,7 +23,7 @@ type Conn struct {
|
||||
|
||||
const (
|
||||
gDEFAULT_RETRY_INTERVAL = 100 * time.Millisecond // Retry interval.
|
||||
gDEFAULT_READ_BUFFER_SIZE = 64 // (Byte)Buffer size.
|
||||
gDEFAULT_READ_BUFFER_SIZE = 1024 // (Byte)Buffer size.
|
||||
gRECV_ALL_WAIT_TIMEOUT = time.Millisecond // Default interval for reading buffer.
|
||||
)
|
||||
|
||||
@ -83,68 +83,32 @@ func (c *Conn) Send(data []byte, retry ...Retry) (err error) {
|
||||
}
|
||||
|
||||
// Recv receives data from remote address.
|
||||
// The parameter <buffer> is used for customizing the receiving buffer size. The default
|
||||
// buffer size is 1024 byte.
|
||||
//
|
||||
// Note that,
|
||||
// 1. There's package border in UDP protocol, so we can receive a complete package if it specifies length < 0.
|
||||
// 2. If length = 0, it means it receives the data from current buffer and returns immediately.
|
||||
// 3. If length > 0, it means it blocks reading data from connection until length size was received.
|
||||
func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {
|
||||
// There's package border in UDP protocol, we can receive a complete package if specified
|
||||
// buffer size is big enough. VERY NOTE that we should receive the complete package in once
|
||||
// or else the leftover package data would be dropped.
|
||||
func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
|
||||
var err error // Reading error.
|
||||
var size int // Reading size.
|
||||
var index int // Received size.
|
||||
var buffer []byte // Buffer object.
|
||||
var bufferWait bool // Whether buffer reading timeout set.
|
||||
var data []byte // Buffer object.
|
||||
var remoteAddr *net.UDPAddr // Current remote address for reading.
|
||||
|
||||
if length > 0 {
|
||||
buffer = make([]byte, length)
|
||||
if buffer > 0 {
|
||||
data = make([]byte, buffer)
|
||||
} else {
|
||||
buffer = make([]byte, gDEFAULT_READ_BUFFER_SIZE)
|
||||
data = make([]byte, gDEFAULT_READ_BUFFER_SIZE)
|
||||
}
|
||||
|
||||
for {
|
||||
if length < 0 && index > 0 {
|
||||
bufferWait = true
|
||||
if err = c.SetReadDeadline(time.Now().Add(c.recvBufferWait)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
size, remoteAddr, err = c.ReadFromUDP(buffer[index:])
|
||||
size, remoteAddr, err = c.ReadFromUDP(data)
|
||||
if err == nil {
|
||||
c.remoteAddr = remoteAddr
|
||||
}
|
||||
if size > 0 {
|
||||
index += size
|
||||
if length > 0 {
|
||||
// It reads til <length> size if <length> is specified.
|
||||
if index == length {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if index >= gDEFAULT_READ_BUFFER_SIZE {
|
||||
// If it exceeds the buffer size, it then automatically increases its buffer size.
|
||||
buffer = append(buffer, make([]byte, gDEFAULT_READ_BUFFER_SIZE)...)
|
||||
} else {
|
||||
// It returns immediately if received size is lesser than buffer size.
|
||||
if !bufferWait {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// Connection closed.
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
// Re-set the timeout when reading data.
|
||||
if bufferWait && isTimeout(err) {
|
||||
if err = c.SetReadDeadline(c.recvDeadline); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
if len(retry) > 0 {
|
||||
// It fails even it retried.
|
||||
if retry[0].Count == 0 {
|
||||
@ -159,12 +123,9 @@ func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {
|
||||
}
|
||||
break
|
||||
}
|
||||
// Just read once from buffer.
|
||||
if length == 0 {
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
return buffer[:index], err
|
||||
return data[:size], err
|
||||
}
|
||||
|
||||
// SendRecv writes data to connection and blocks reading response.
|
||||
|
||||
@ -52,14 +52,3 @@ func SendRecv(address string, data []byte, receive int, retry ...Retry) ([]byte,
|
||||
defer conn.Close()
|
||||
return conn.SendRecv(data, receive, retry...)
|
||||
}
|
||||
|
||||
// isTimeout checks whether given <err> is a timeout error.
|
||||
func isTimeout(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ func Test_Basic(t *testing.T) {
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -71,3 +71,36 @@ func Test_Basic(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// If the read buffer size is less than the sent package size,
|
||||
// the rest data would be dropped.
|
||||
func Test_Buffer(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gudp.NewServer(fmt.Sprintf("127.0.0.1:%d", p), func(conn *gudp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
data, err := conn.Recv(1)
|
||||
if len(data) > 0 {
|
||||
if err := conn.Send(data); err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
go s.Run()
|
||||
defer s.Close()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
result, err := gudp.SendRecv(fmt.Sprintf("127.0.0.1:%d", p), []byte("123"), -1)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(result), "1")
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := gudp.SendRecv(fmt.Sprintf("127.0.0.1:%d", p), []byte("456"), -1)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(result), "4")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user