2019-04-28 23:55:23 +08:00
|
|
|
|
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
|
|
package gtcp
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"fmt"
|
|
|
|
|
"time"
|
2019-06-22 22:05:39 +08:00
|
|
|
|
|
2019-06-29 23:35:32 +08:00
|
|
|
|
"github.com/gogf/gf/g/errors/gerror"
|
2019-04-28 23:55:23 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2019-05-20 08:59:16 +08:00
|
|
|
|
// 默认允许最大的简单协议包大小(byte), 65535 byte
|
2019-06-03 23:53:59 +08:00
|
|
|
|
gPKG_MAX_DATA_SIZE = 65535
|
|
|
|
|
// 简单协议包头大小
|
2019-06-19 09:06:52 +08:00
|
|
|
|
gPKG_HEADER_SIZE = 3
|
2019-04-28 23:55:23 +08:00
|
|
|
|
)
|
|
|
|
|
|
2019-05-20 08:59:16 +08:00
|
|
|
|
// 数据读取选项
|
2019-06-03 23:53:59 +08:00
|
|
|
|
type PkgOption struct {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
MaxSize int // (byte)数据读取的最大包大小,最大不能超过3字节(0xFFFFFF,15MB),默认为65535byte
|
|
|
|
|
Retry Retry // 失败重试
|
2019-05-20 08:59:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 23:53:59 +08:00
|
|
|
|
// getPkgOption wraps and returns the PkgOption.
|
2019-05-20 08:59:16 +08:00
|
|
|
|
// If no option given, it returns a new option with default value.
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func getPkgOption(option ...PkgOption) (*PkgOption, error) {
|
2019-06-03 23:53:59 +08:00
|
|
|
|
pkgOption := PkgOption{}
|
2019-05-20 08:59:16 +08:00
|
|
|
|
if len(option) > 0 {
|
|
|
|
|
pkgOption = option[0]
|
|
|
|
|
}
|
|
|
|
|
if pkgOption.MaxSize == 0 {
|
2019-06-03 23:53:59 +08:00
|
|
|
|
pkgOption.MaxSize = gPKG_MAX_DATA_SIZE
|
2019-05-20 08:59:16 +08:00
|
|
|
|
} else if pkgOption.MaxSize > 0xFFFFFF {
|
|
|
|
|
return nil, fmt.Errorf(`package size %d exceeds allowed max size %d`, pkgOption.MaxSize, 0xFFFFFF)
|
|
|
|
|
}
|
|
|
|
|
return &pkgOption, nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-28 23:55:23 +08:00
|
|
|
|
// 根据简单协议发送数据包。
|
2019-06-03 23:53:59 +08:00
|
|
|
|
//
|
|
|
|
|
// 简单协议数据格式:数据长度(24bit)|数据字段(变长)。
|
|
|
|
|
//
|
2019-04-28 23:55:23 +08:00
|
|
|
|
// 注意:
|
2019-06-03 23:53:59 +08:00
|
|
|
|
// 1. "数据长度"仅为"数据字段"的长度,不包含头信息的长度字段3字节。
|
|
|
|
|
// 2. 由于"数据长度"为3字节,并且使用的BigEndian字节序,因此这里最后返回的buffer使用了buffer[1:]。
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (c *Conn) SendPkg(data []byte, option ...PkgOption) error {
|
2019-05-20 08:59:16 +08:00
|
|
|
|
pkgOption, err := getPkgOption(option...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
length := len(data)
|
2019-06-03 23:53:59 +08:00
|
|
|
|
if length > pkgOption.MaxSize {
|
2019-06-21 22:23:07 +08:00
|
|
|
|
return fmt.Errorf(`data size %d exceeds max pkg size %d`, length, gPKG_MAX_DATA_SIZE)
|
2019-05-20 08:59:16 +08:00
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
buffer := make([]byte, gPKG_HEADER_SIZE+1+len(data))
|
|
|
|
|
binary.BigEndian.PutUint32(buffer[0:], uint32(length))
|
|
|
|
|
copy(buffer[gPKG_HEADER_SIZE+1:], data)
|
2019-05-20 08:59:16 +08:00
|
|
|
|
if pkgOption.Retry.Count > 0 {
|
2019-06-04 23:33:46 +08:00
|
|
|
|
return c.Send(buffer[1:], pkgOption.Retry)
|
2019-05-20 08:59:16 +08:00
|
|
|
|
}
|
2019-06-03 23:53:59 +08:00
|
|
|
|
//fmt.Println("SendPkg:", buffer[1:])
|
2019-05-20 08:59:16 +08:00
|
|
|
|
return c.Send(buffer[1:])
|
2019-04-28 23:55:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简单协议: 带超时时间的数据发送
|
2019-06-21 22:23:07 +08:00
|
|
|
|
func (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) {
|
2019-06-04 23:33:46 +08:00
|
|
|
|
if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-06-21 22:23:07 +08:00
|
|
|
|
defer func() {
|
2019-06-29 23:35:32 +08:00
|
|
|
|
err = gerror.Wrap(c.SetSendDeadline(time.Time{}), "SetSendDeadline error")
|
2019-06-21 22:23:07 +08:00
|
|
|
|
}()
|
|
|
|
|
err = c.SendPkg(data, option...)
|
|
|
|
|
return
|
2019-04-28 23:55:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简单协议: 发送数据并等待接收返回数据
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) {
|
2019-05-20 08:59:16 +08:00
|
|
|
|
if err := c.SendPkg(data, option...); err == nil {
|
|
|
|
|
return c.RecvPkg(option...)
|
2019-04-28 23:55:23 +08:00
|
|
|
|
} else {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简单协议: 发送数据并等待接收返回数据(带返回超时等待时间)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {
|
2019-05-20 08:59:16 +08:00
|
|
|
|
if err := c.SendPkg(data, option...); err == nil {
|
|
|
|
|
return c.RecvPkgWithTimeout(timeout, option...)
|
2019-04-28 23:55:23 +08:00
|
|
|
|
} else {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简单协议: 获取一个数据包。
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error) {
|
|
|
|
|
var temp []byte
|
2019-05-20 08:59:16 +08:00
|
|
|
|
var length int
|
|
|
|
|
pkgOption, err := getPkgOption(option...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-04-28 23:55:23 +08:00
|
|
|
|
for {
|
|
|
|
|
// 先根据对象的缓冲区数据进行计算
|
|
|
|
|
for {
|
2019-06-03 23:53:59 +08:00
|
|
|
|
if len(c.buffer) >= gPKG_HEADER_SIZE {
|
|
|
|
|
// 注意"数据长度"为3个字节,不满足4个字节的uint32类型,因此这里"低位"补0
|
2019-05-20 08:59:16 +08:00
|
|
|
|
length = int(binary.BigEndian.Uint32([]byte{0, c.buffer[0], c.buffer[1], c.buffer[2]}))
|
|
|
|
|
// 解析的大小是否符合规范,清空从该连接接收到的所有数据包
|
2019-06-03 23:53:59 +08:00
|
|
|
|
if length < 0 || length > pkgOption.MaxSize {
|
2019-05-20 08:59:16 +08:00
|
|
|
|
c.buffer = c.buffer[:0]
|
|
|
|
|
return nil, fmt.Errorf(`invalid package size %d`, length)
|
2019-04-28 23:55:23 +08:00
|
|
|
|
}
|
|
|
|
|
// 不满足包大小,需要继续读取
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if len(c.buffer) < length+gPKG_HEADER_SIZE {
|
2019-04-28 23:55:23 +08:00
|
|
|
|
break
|
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
result = c.buffer[gPKG_HEADER_SIZE : gPKG_HEADER_SIZE+length]
|
|
|
|
|
c.buffer = c.buffer[gPKG_HEADER_SIZE+length:]
|
2019-04-28 23:55:23 +08:00
|
|
|
|
return
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 读取系统socket缓冲区的完整数据
|
2019-06-03 23:53:59 +08:00
|
|
|
|
temp, err = c.Recv(0, pkgOption.Retry)
|
2019-04-28 23:55:23 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if len(temp) > 0 {
|
|
|
|
|
c.buffer = append(c.buffer, temp...)
|
|
|
|
|
}
|
2019-04-29 23:54:47 +08:00
|
|
|
|
//fmt.Println("RecvPkg:", c.buffer)
|
2019-04-28 23:55:23 +08:00
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简单协议: 带超时时间的消息包获取
|
2019-06-21 22:23:07 +08:00
|
|
|
|
func (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) {
|
2019-06-04 23:33:46 +08:00
|
|
|
|
if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-06-21 22:23:07 +08:00
|
|
|
|
defer func() {
|
2019-06-29 23:35:32 +08:00
|
|
|
|
err = gerror.Wrap(c.SetRecvDeadline(time.Time{}), "SetRecvDeadline error")
|
2019-06-21 22:23:07 +08:00
|
|
|
|
}()
|
|
|
|
|
data, err = c.RecvPkg(option...)
|
|
|
|
|
return
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|