gf/net/gtcp/gtcp_conn_pkg.go

174 lines
5.4 KiB
Go
Raw Normal View History

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-07-29 21:01:19 +08:00
"github.com/gogf/gf/errors/gerror"
2019-04-28 23:55:23 +08:00
)
const (
2019-05-20 08:59:16 +08:00
// 默认允许最大的简单协议包大小(byte), 65535 byte
2019-07-09 14:03:43 +08:00
gPKG_DEFAULT_MAX_DATA_SIZE = 65535
// 默认简单协议包头大小
gPKG_DEFAULT_HEADER_SIZE = 2
// 协议头最大大小
gPKG_MAX_HEADER_SIZE = 4
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-07-09 14:03:43 +08:00
HeaderSize int // 自定义头大小(默认为2字节最大不能超过4字节)
MaxDataSize int // (byte)数据读取的最大包大小默认最大不能超过2字节(65535 byte)
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]
}
2019-07-09 14:03:43 +08:00
if pkgOption.HeaderSize == 0 {
pkgOption.HeaderSize = gPKG_DEFAULT_HEADER_SIZE
}
if pkgOption.MaxDataSize == 0 {
pkgOption.MaxDataSize = gPKG_DEFAULT_MAX_DATA_SIZE
} else if pkgOption.MaxDataSize > 0xFFFFFF {
return nil, fmt.Errorf(`package size %d exceeds allowed max size %d`, pkgOption.MaxDataSize, 0xFFFFFF)
2019-05-20 08:59:16 +08:00
}
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-07-09 14:03:43 +08:00
if length > pkgOption.MaxDataSize {
return fmt.Errorf(`data size %d exceeds max pkg size %d`, length, pkgOption.MaxDataSize)
2019-05-20 08:59:16 +08:00
}
2019-07-09 14:03:43 +08:00
offset := gPKG_MAX_HEADER_SIZE - pkgOption.HeaderSize
buffer := make([]byte, gPKG_MAX_HEADER_SIZE+len(data))
2019-06-19 09:06:52 +08:00
binary.BigEndian.PutUint32(buffer[0:], uint32(length))
2019-07-09 14:03:43 +08:00
copy(buffer[gPKG_MAX_HEADER_SIZE:], data)
2019-05-20 08:59:16 +08:00
if pkgOption.Retry.Count > 0 {
2019-07-09 14:03:43 +08:00
return c.Send(buffer[offset:], pkgOption.Retry)
2019-05-20 08:59:16 +08:00
}
2019-07-09 14:03:43 +08:00
//fmt.Println("SendPkg:", buffer[offset:])
return c.Send(buffer[offset:])
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-07-09 14:03:43 +08:00
if len(c.buffer) >= pkgOption.HeaderSize {
// 不满足4个字节的uint32类型因此这里"低位"补0
if length <= 0 {
switch pkgOption.HeaderSize {
case 1:
length = int(binary.BigEndian.Uint32([]byte{0, 0, 0, c.buffer[0]}))
case 2:
length = int(binary.BigEndian.Uint32([]byte{0, 0, c.buffer[0], c.buffer[1]}))
case 3:
length = int(binary.BigEndian.Uint32([]byte{0, c.buffer[0], c.buffer[1], c.buffer[2]}))
default:
length = int(binary.BigEndian.Uint32([]byte{c.buffer[0], c.buffer[1], c.buffer[2], c.buffer[3]}))
}
}
2019-05-20 08:59:16 +08:00
// 解析的大小是否符合规范,清空从该连接接收到的所有数据包
2019-07-09 14:03:43 +08:00
if length < 0 || length > pkgOption.MaxDataSize {
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-07-09 14:03:43 +08:00
if len(c.buffer) < length+pkgOption.HeaderSize {
2019-04-28 23:55:23 +08:00
break
}
2019-07-09 14:03:43 +08:00
result = c.buffer[pkgOption.HeaderSize : pkgOption.HeaderSize+length]
c.buffer = c.buffer[pkgOption.HeaderSize+length:]
length = 0
2019-04-28 23:55:23 +08:00
return
} else {
break
}
}
2019-07-09 14:03:43 +08:00
// 读取系统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...)
}
//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
}