150 lines
2.8 KiB
Go
150 lines
2.8 KiB
Go
// frame.go 帧协议,wire format 与 zonat 桥接帧完全一致
|
||
// (ver(1) + cmd(1) + length(2, LE) + sid(4, LE) + data)。
|
||
// 本文件取自 zonat client/internal/frame 的本地修复副本,仅裁掉未用方法。
|
||
package agent
|
||
|
||
import (
|
||
"encoding/binary"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"io"
|
||
"net"
|
||
)
|
||
|
||
const FrameVersion byte = 1
|
||
|
||
// 帧头部
|
||
const (
|
||
sizeOfVer = 1
|
||
sizeOfCmd = 1
|
||
sizeOfLength = 2
|
||
sizeOfSid = 4
|
||
headerSize = sizeOfVer + sizeOfCmd + sizeOfSid + sizeOfLength
|
||
)
|
||
|
||
const (
|
||
frameBufSize = 0x10000
|
||
)
|
||
|
||
type Frame struct {
|
||
ver byte
|
||
cmd byte
|
||
sid uint32
|
||
data []byte
|
||
}
|
||
|
||
func NewFrame(version byte, cmd byte, sid uint32) Frame {
|
||
return Frame{ver: version, cmd: cmd, sid: sid}
|
||
}
|
||
|
||
// ReadFrame 读取一帧。头部与数据均用 ReadFull,防止单次 Read 短读导致解析错乱,
|
||
// 也不会把后续帧的数据读进缓冲丢弃。
|
||
func ReadFrame(conn net.Conn) (Frame, error) {
|
||
f := NewFrame(0, 0, 0)
|
||
hdr := RawHeader{}
|
||
if _, err := io.ReadFull(conn, hdr[:]); err != nil {
|
||
return f, err
|
||
}
|
||
|
||
f.ver = hdr.Version()
|
||
f.cmd = hdr.Cmd()
|
||
f.sid = hdr.StreamID()
|
||
|
||
length := int(hdr.Length())
|
||
if length == 0 {
|
||
return f, nil
|
||
}
|
||
data := make([]byte, length)
|
||
if _, err := io.ReadFull(conn, data); err != nil {
|
||
return f, err
|
||
}
|
||
f.data = data
|
||
return f, nil
|
||
}
|
||
|
||
func WriteFrame(conn net.Conn, frame Frame) error {
|
||
hdr := RawHeader{}
|
||
hdr[0] = frame.ver
|
||
hdr[1] = frame.cmd
|
||
binary.LittleEndian.PutUint16(hdr[2:], uint16(len(frame.data)))
|
||
binary.LittleEndian.PutUint32(hdr[4:], frame.sid)
|
||
|
||
buf := hdr.Bytes()
|
||
buf = append(buf, frame.data...)
|
||
_, err := conn.Write(buf)
|
||
return err
|
||
}
|
||
|
||
func (f *Frame) Version() byte {
|
||
return f.ver
|
||
}
|
||
|
||
func (f *Frame) Cmd() byte {
|
||
return f.cmd
|
||
}
|
||
|
||
func (f *Frame) Length() uint16 {
|
||
return uint16(len(f.data))
|
||
}
|
||
|
||
func (f *Frame) Data() []byte {
|
||
return f.data
|
||
}
|
||
|
||
func (f *Frame) StreamID() uint32 {
|
||
return f.sid
|
||
}
|
||
|
||
func (f *Frame) SetData(data []byte) error {
|
||
if len(data) > frameBufSize-1 {
|
||
return fmt.Errorf("超出最大长度:%d", frameBufSize-1)
|
||
}
|
||
f.data = data
|
||
return nil
|
||
}
|
||
|
||
func (f *Frame) Marshal(v any) error {
|
||
buf, err := json.Marshal(v)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return f.SetData(buf)
|
||
}
|
||
|
||
func (f *Frame) Unmarshal(v any) error {
|
||
if len(f.data) == 0 {
|
||
return errors.New("没有数据")
|
||
}
|
||
return json.Unmarshal(f.data, v)
|
||
}
|
||
|
||
func (f *Frame) String() string {
|
||
return fmt.Sprintf("Version:%d Cmd:%d StreamID:%d Length:%d",
|
||
f.Version(), f.Cmd(), f.StreamID(), f.Length())
|
||
}
|
||
|
||
type RawHeader [headerSize]byte
|
||
|
||
func (h RawHeader) Version() byte {
|
||
return h[0]
|
||
}
|
||
|
||
func (h RawHeader) Cmd() byte {
|
||
return h[1]
|
||
}
|
||
|
||
func (h RawHeader) Length() uint16 {
|
||
return binary.LittleEndian.Uint16(h[2:])
|
||
}
|
||
|
||
func (h RawHeader) StreamID() uint32 {
|
||
return binary.LittleEndian.Uint32(h[4:])
|
||
}
|
||
|
||
func (h RawHeader) Bytes() []byte {
|
||
buf := make([]byte, headerSize)
|
||
copy(buf, h[:])
|
||
return buf
|
||
}
|