Files
zonat/agent/frame.go
T

150 lines
2.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
}