improve package gudp

This commit is contained in:
John
2020-03-11 23:54:35 +08:00
parent 13ab139afc
commit f44c19868c
3 changed files with 48 additions and 65 deletions

View File

@ -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.

View File

@ -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
}

View File

@ -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")
})
}