github.com/zhongdalu/gf@v1.0.0/g/net/gtcp/gtcp_conn_pkg.go (about) 1 // Copyright 2019 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf. 6 7 package gtcp 8 9 import ( 10 "encoding/binary" 11 "fmt" 12 "time" 13 14 "github.com/zhongdalu/gf/g/errors/gerror" 15 ) 16 17 const ( 18 // 默认允许最大的简单协议包大小(byte), 65535 byte 19 gPKG_DEFAULT_MAX_DATA_SIZE = 65535 20 // 默认简单协议包头大小 21 gPKG_DEFAULT_HEADER_SIZE = 2 22 // 协议头最大大小 23 gPKG_MAX_HEADER_SIZE = 4 24 ) 25 26 // 数据读取选项 27 type PkgOption struct { 28 HeaderSize int // 自定义头大小(默认为2字节,最大不能超过4字节) 29 MaxDataSize int // (byte)数据读取的最大包大小,默认最大不能超过2字节(65535 byte) 30 Retry Retry // 失败重试 31 } 32 33 // getPkgOption wraps and returns the PkgOption. 34 // If no option given, it returns a new option with default value. 35 func getPkgOption(option ...PkgOption) (*PkgOption, error) { 36 pkgOption := PkgOption{} 37 if len(option) > 0 { 38 pkgOption = option[0] 39 } 40 if pkgOption.HeaderSize == 0 { 41 pkgOption.HeaderSize = gPKG_DEFAULT_HEADER_SIZE 42 } 43 if pkgOption.MaxDataSize == 0 { 44 pkgOption.MaxDataSize = gPKG_DEFAULT_MAX_DATA_SIZE 45 } else if pkgOption.MaxDataSize > 0xFFFFFF { 46 return nil, fmt.Errorf(`package size %d exceeds allowed max size %d`, pkgOption.MaxDataSize, 0xFFFFFF) 47 } 48 return &pkgOption, nil 49 } 50 51 // 根据简单协议发送数据包。 52 // 53 // 简单协议数据格式:数据长度(24bit)|数据字段(变长)。 54 // 55 // 注意: 56 // 1. "数据长度"仅为"数据字段"的长度,不包含头信息的长度字段3字节。 57 // 2. 由于"数据长度"为3字节,并且使用的BigEndian字节序,因此这里最后返回的buffer使用了buffer[1:]。 58 func (c *Conn) SendPkg(data []byte, option ...PkgOption) error { 59 pkgOption, err := getPkgOption(option...) 60 if err != nil { 61 return err 62 } 63 length := len(data) 64 if length > pkgOption.MaxDataSize { 65 return fmt.Errorf(`data size %d exceeds max pkg size %d`, length, pkgOption.MaxDataSize) 66 } 67 offset := gPKG_MAX_HEADER_SIZE - pkgOption.HeaderSize 68 buffer := make([]byte, gPKG_MAX_HEADER_SIZE+len(data)) 69 binary.BigEndian.PutUint32(buffer[0:], uint32(length)) 70 copy(buffer[gPKG_MAX_HEADER_SIZE:], data) 71 if pkgOption.Retry.Count > 0 { 72 return c.Send(buffer[offset:], pkgOption.Retry) 73 } 74 //fmt.Println("SendPkg:", buffer[offset:]) 75 return c.Send(buffer[offset:]) 76 } 77 78 // 简单协议: 带超时时间的数据发送 79 func (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) { 80 if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil { 81 return err 82 } 83 defer func() { 84 err = gerror.Wrap(c.SetSendDeadline(time.Time{}), "SetSendDeadline error") 85 }() 86 err = c.SendPkg(data, option...) 87 return 88 } 89 90 // 简单协议: 发送数据并等待接收返回数据 91 func (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) { 92 if err := c.SendPkg(data, option...); err == nil { 93 return c.RecvPkg(option...) 94 } else { 95 return nil, err 96 } 97 } 98 99 // 简单协议: 发送数据并等待接收返回数据(带返回超时等待时间) 100 func (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) { 101 if err := c.SendPkg(data, option...); err == nil { 102 return c.RecvPkgWithTimeout(timeout, option...) 103 } else { 104 return nil, err 105 } 106 } 107 108 // 简单协议: 获取一个数据包。 109 func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error) { 110 var temp []byte 111 var length int 112 pkgOption, err := getPkgOption(option...) 113 if err != nil { 114 return nil, err 115 } 116 for { 117 // 先根据对象的缓冲区数据进行计算 118 for { 119 if len(c.buffer) >= pkgOption.HeaderSize { 120 // 不满足4个字节的uint32类型,因此这里"低位"补0 121 if length <= 0 { 122 switch pkgOption.HeaderSize { 123 case 1: 124 length = int(binary.BigEndian.Uint32([]byte{0, 0, 0, c.buffer[0]})) 125 case 2: 126 length = int(binary.BigEndian.Uint32([]byte{0, 0, c.buffer[0], c.buffer[1]})) 127 case 3: 128 length = int(binary.BigEndian.Uint32([]byte{0, c.buffer[0], c.buffer[1], c.buffer[2]})) 129 default: 130 length = int(binary.BigEndian.Uint32([]byte{c.buffer[0], c.buffer[1], c.buffer[2], c.buffer[3]})) 131 } 132 } 133 // 解析的大小是否符合规范,清空从该连接接收到的所有数据包 134 if length < 0 || length > pkgOption.MaxDataSize { 135 c.buffer = c.buffer[:0] 136 return nil, fmt.Errorf(`invalid package size %d`, length) 137 } 138 // 不满足包大小,需要继续读取 139 if len(c.buffer) < length+pkgOption.HeaderSize { 140 break 141 } 142 result = c.buffer[pkgOption.HeaderSize : pkgOption.HeaderSize+length] 143 c.buffer = c.buffer[pkgOption.HeaderSize+length:] 144 length = 0 145 return 146 } else { 147 break 148 } 149 } 150 // 读取系统socket当前缓冲区的数据 151 temp, err = c.Recv(0, pkgOption.Retry) 152 if err != nil { 153 break 154 } 155 if len(temp) > 0 { 156 c.buffer = append(c.buffer, temp...) 157 } 158 //fmt.Println("RecvPkg:", c.buffer) 159 } 160 return 161 } 162 163 // 简单协议: 带超时时间的消息包获取 164 func (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) { 165 if err := c.SetRecvDeadline(time.Now().Add(timeout)); err != nil { 166 return nil, err 167 } 168 defer func() { 169 err = gerror.Wrap(c.SetRecvDeadline(time.Time{}), "SetRecvDeadline error") 170 }() 171 data, err = c.RecvPkg(option...) 172 return 173 }