package pomeloPacket import ( "bytes" "fmt" "io" "net" cerr "github.com/mhaya/error" ) type ( Packet struct { typ Type len int data []byte } ) func (p *Packet) Type() Type { return p.typ } func (p *Packet) Len() int { return p.len } func (p *Packet) Data() []byte { return p.data } func (p *Packet) SetData(data []byte) { p.data = data } // String represents the Packet's in text mode. func (p *Packet) String() string { return fmt.Sprintf("packet type: %s, length: %d, data: %s", TypeName(p.typ), p.len, string(p.data)) } func Decode(data []byte) ([]*Packet, error) { buf := bytes.NewBuffer(data) var ( packets []*Packet err error ) // check length if buf.Len() < HeadLength { return nil, err } size, typ, err := forward(buf) if err != nil { return nil, err } for size <= buf.Len() { pkg := &Packet{ typ: typ, len: size, data: buf.Next(size), } packets = append(packets, pkg) if buf.Len() < HeadLength { break } size, typ, err = forward(buf) if err != nil { return nil, err } } return packets, nil } // Encode create a packet.Packet from the raw bytes slice and then encode to network bytes slice // Protocol refs: https://github.com/NetEase/pomelo/wiki/Communication-Protocol // // --|----------------|-- // --------|------------------------|-------- // 1 byte packet type, 3 bytes packet data length(big end), and data segment func Encode(typ byte, data []byte) ([]byte, error) { if typ < Handshake || typ > Kick { return nil, cerr.PacketWrongType } if len(data) > MaxPacketSize { return nil, cerr.PacketSizeExceed } pkg := &Packet{ typ: typ, len: len(data), } // header+body = 4 + len(body) buf := make([]byte, pkg.len+HeadLength) //第一个字节存放消息类型 buf[0] = pkg.Type() //2~4 字节 存放消息长度 copy(buf[1:HeadLength], IntToBytes(pkg.len)) //4字节之后存放的内容是消息体 copy(buf[HeadLength:], data) return buf, nil } func Read(conn net.Conn) ([]*Packet, bool, error) { header, err := io.ReadAll(io.LimitReader(conn, int64(HeadLength))) if err != nil { return nil, true, err } // if the header has no data, we can consider it as a closed connection if len(header) == 0 { return nil, true, cerr.PacketConnectClosed } msgSize, err := ParseHeader(header) if err != nil { return nil, true, err } msgData, err := io.ReadAll(io.LimitReader(conn, int64(msgSize))) if err != nil { return nil, true, err } if len(msgData) < msgSize { return nil, true, cerr.PacketMsgSmallerThanExpected } header = append(header, msgData...) packets, err := Decode(header) if err != nil { return nil, false, err } return packets, false, nil }