User Tools

Site Tools


,

Binary protocol example, adaptation for Golang

As example like Message protocol prototype

Sender order:

  1. Prepare payload
  2. Get payload size
  3. Prepare and pack header
  4. Send header and
  5. Send payload (by part or all)

Receiver order:

  1. Receive and unpack header
  2. Check header if need
  3. Get payload size
  4. Route if need
  5. Receive payload (by part or all, if need)
  6. Process
msgp.go
/*
 * Author, Copyright: Oleg Borodin <onborodin@gmail.com>
 */
package main
 
import (
    "bytes"
    "encoding/json"
    "encoding/binary"
    "fmt"
 
    "github.com/vmihailenco/msgpack/v5"
)
 
const (
    AuthKeyLength       uint    = 4
    PacketHeaderLength  uint    = 30
)
 
type SourceType     uint16
type IdType         uint32
type AuthKeyType    [AuthKeyLength]byte
 
type PacketMType    uint32
type PacketSType    uint32
type RequestLength  uint64
 
type CRCType        uint64
 
//type Packet struct {
//    Header      PacketHeader
//    HeaderCRC   CRCType
//    Payload     PacketPayload
//}
 
type PacketHeader struct {
    SourceClass SourceType      `json:"sourceClass"`    // Source class
    SourceId    IdType          `json:"sourceId"`       // Adresses
    DestinId    IdType          `json:"destId"`
    AuthKey     AuthKeyType     `json:"authKey"`
 
    MType       PacketMType     `json:"mType"`          // Main category
    SType       PacketSType     `json:"sType"`          // Sub category 
    PLength     RequestLength   `json:"pLength"`        // Payload length
}
 
func (this *PacketHeader) Pack() []byte {
    var buffer []byte
    packetWriter := bytes.NewBuffer(buffer)
    _ = binary.Write(packetWriter, binary.BigEndian, this.SourceClass)
    _ = binary.Write(packetWriter, binary.BigEndian, this.SourceId)
    _ = binary.Write(packetWriter, binary.BigEndian, this.DestinId)
    _ = binary.Write(packetWriter, binary.BigEndian, this.AuthKey)
    _ = binary.Write(packetWriter, binary.BigEndian, this.MType)
    _ = binary.Write(packetWriter, binary.BigEndian, this.SType)
    _ = binary.Write(packetWriter, binary.BigEndian, this.PLength)
    return packetWriter.Bytes()
}
 
func (this *PacketHeader) ToJSON() string {
    jsonBytes, _ := json.MarshalIndent(this, "", "    ")
    return string(jsonBytes)
}
 
func UnpackPacketHeader(buffer []byte) *PacketHeader {
   var packetHeader PacketHeader
    headerReader := bytes.NewBuffer(buffer)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.SourceClass)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.SourceId)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.DestinId)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.AuthKey)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.MType)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.SType)
    _ = binary.Read(headerReader, binary.BigEndian, &packetHeader.PLength)
    return &packetHeader
}
 
type PacketPayload []byte
 
// Service classes
const (
 
    GwNode      SourceType  = 33
    DateNode    SourceType  = 34
    // ...
)
// Main categories of requests and replies
const (
    RawBinaryPacket     PacketMType = 1
    FileWDescrPacket    PacketMType = 2
    FileBatchPacket     PacketMType = 3
    JSONRPCPacket       PacketMType = 4
    MsgpackRPCPacket    PacketMType = 5
    // ...
)
// Example of RPC packets over Msgpack
const (
    HelloRequestType    PacketSType = 1
    HelloResponseType   PacketSType = 2
 
    AddRequestType      PacketSType = 3
    AddResponseType     PacketSType = 4
    // ...
)
 
// 
type RPCHelloRequest struct {
    Message string          `msgpack:"message"`
}
type RPCHelloResponce struct {
    Message string          `msgpack:"message"`
}
 
type AddRequest struct {
    Message string          `msgpack:"message"`
}
 
func main() {
    // Pack payload
    var rpcRequest RPCHelloRequest
    rpcRequest.Message = "hello"
    payloadBytes, _ := msgpack.Marshal(&rpcRequest)
 
    // Define packet
    var packetHeader PacketHeader
    packetHeader.MType          = MsgpackRPCPacket
    packetHeader.SType          = HelloRequestType
    packetHeader.AuthKey        = [AuthKeyLength]byte{ 12, 12, 12, 12 }
    packetHeader.SourceClass    = GwNode
    packetHeader.SourceId       = 25                    // Example
    packetHeader.DestinId       = 45                    // Example
    packetHeader.PLength        = RequestLength(len(payloadBytes))
 
    fmt.Println(packetHeader.ToJSON())
 
    // Pack header
    headerBytes := packetHeader.Pack()
 
    fmt.Println("#header:", headerBytes)
    fmt.Println("#payload:", payloadBytes)
 
    // Make pseudo socket
    networkBuffer := make([]byte, 0)
    networkSocket := bytes.NewBuffer(networkBuffer)
 
    // Write to pseudo socket
    networkSocket.Write(headerBytes)
    networkSocket.Write(payloadBytes)
 
    // Packet in air
    packetInAir := networkSocket.Bytes()
    fmt.Println("#packet in air:\n", packetInAir)
 
    // Make pseudo socket for reading
    socketReader := bytes.NewReader(packetInAir)
 
    // Read packet header from pseudo socket 
    headerBuffer := make([]byte, PacketHeaderLength)
    _, _ = socketReader.Read(headerBuffer) // Wo control of size and error state
    fmt.Println("#header:", headerBuffer)
 
    // Unpack header
    unpackedHeader := UnpackPacketHeader(headerBuffer) 
    fmt.Println(unpackedHeader.ToJSON())
 
    // Read payload
    payloadBuffer := make([]byte, unpackedHeader.PLength)
    _, _ = socketReader.Read(payloadBuffer)
    fmt.Println("#payload:", payloadBuffer)
}
//EOF

Out

$ go run msgp.go
#header: [0 33 0 0 0 25 0 0 0 45 12 12 12 12 0 0 0 5 0 0 0 1 0 0 0 0 0 0 0 15]
{
    "sourceClass": 33,
    "sourceId": 25,
    "destId": 45,
    "authKey": [
        12,
        12,
        12,
        12
    ],
    "mType": 5,
    "sType": 1,
    "pLength": 15
}
#payload: [129 167 109 101 115 115 97 103 101 165 104 101 108 108 111]

#packet in air:
 [0 33 0 0 0 25 0 0 0 45 12 12 12 12 0 0 0 5 0 0 0 1 0 0 0 0 0 0 0 15 129 167 109 101 115 115 97 103 101 165 104 101 108 108 111]

#header: [0 33 0 0 0 25 0 0 0 45 12 12 12 12 0 0 0 5 0 0 0 1 0 0 0 0 0 0 0 15]
{
    "sourceClass": 33,
    "sourceId": 25,
    "destId": 45,
    "authKey": [
        12,
        12,
        12,
        12
    ],
    "mType": 5,
    "sType": 1,
    "pLength": 15
}
#payload: [129 167 109 101 115 115 97 103 101 165 104 101 108 108 111]