github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/core/protocol/message/serialization.go (about) 1 package message 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "fmt" 7 "github.com/nyan233/littlerpc/core/container" 8 "github.com/nyan233/littlerpc/core/utils/convert" 9 "math" 10 ) 11 12 // MarshaToMux 此API只会序列化Mux功能需要的数据 13 func MarshaToMux(msg *Message, payloads *container.Slice[byte]) error { 14 if payloads.Cap() < msg.MinMux() { 15 *payloads = make([]byte, 0, msg.MinMux()) 16 } 17 msg.GetAndSetLength() 18 *payloads = append(*payloads, msg.scope[:]...) 19 *payloads = (*payloads)[:msg.MinMux()] 20 binary.BigEndian.PutUint64((*payloads)[2:10], msg.msgId) 21 binary.BigEndian.PutUint32((*payloads)[10:14], msg.payloadLength) 22 return nil 23 } 24 25 // UnmarshalFromMux 此API之后反序列化Mux功能所需要的数据 26 func UnmarshalFromMux(data container.Slice[byte], msg *Message) error { 27 if data.Len() < msg.MinMux() { 28 return errors.New("mux message is bad") 29 } 30 copy(msg.scope[:], data[:_ScopeLength]) 31 msg.msgId = binary.BigEndian.Uint64(data[_ScopeLength:10]) 32 msg.payloadLength = binary.BigEndian.Uint32(data[10:14]) 33 return nil 34 } 35 36 // Unmarshal 从字节Slice中解码出Message,并返回载荷数据的起始地址 37 func Unmarshal(p container.Slice[byte], msg *Message) error { 38 if p.Len() == 0 || msg == nil { 39 return errors.New("data or message is nil") 40 } 41 if p.Len() < msg.BaseLength() { 42 return errors.New("data Length < baseLen") 43 } 44 err := UnmarshalFromMux(p, msg) 45 if err != nil { 46 return err 47 } 48 p = p[msg.MinMux():] 49 // NameLayout 50 serviceNameLen := p[0] 51 p = p[_ServiceName:] 52 if p.Len() < int(serviceNameLen) { 53 return errors.New("service name Length greater than p") 54 } 55 msg.SetServiceName(string(p[:serviceNameLen])) 56 p = p[serviceNameLen:] 57 // 有多少个元数据 58 // 在可变长数据之后, 需要校验 59 if p.Len() < _Metadata { 60 return errors.New("p Length less than 1") 61 } 62 nMetaData := p[0] 63 p = p[_Metadata:] 64 for i := 0; i < int(nMetaData); i++ { 65 if p.Len() < 8 { 66 return errors.New("p Length less than 8 on nMetaData") 67 } 68 keySize := binary.BigEndian.Uint32(p[:4]) 69 valueSize := binary.BigEndian.Uint32(p[4:8]) 70 // 相加防止溢出, 所以需要检查溢出 71 if p.Len() < int(keySize+valueSize) || keySize > math.MaxUint32-valueSize { 72 return errors.New("key and value size overflow") 73 } 74 p = p[8:] 75 msg.MetaData.Store(string(p[:keySize]), string(p[keySize:keySize+valueSize])) 76 p = p[keySize+valueSize:] 77 } 78 // 在可变长数据之后, 需要校验 79 if p.Len() < _PayloadLayout { 80 return errors.New("p Length less than 4 on nArgs") 81 } 82 nArgs := p[0] 83 p = p[_PayloadLayout:] 84 // 为了保证更好的反序列化体验,如果不将layout置0的话 85 // 会导致与Marshal/Unmarshal的结果重叠 86 if msg.payloadLayout != nil { 87 msg.payloadLayout.Reset() 88 } 89 for i := 0; i < int(nArgs); i++ { 90 if p.Len() < 4 { 91 return errors.New("p Length less than 4 on argument layout") 92 } 93 argsSize := binary.BigEndian.Uint32(p[:4]) 94 p = p[4:] 95 msg.payloadLayout = append(msg.payloadLayout, argsSize) 96 } 97 // 不根据参数布局计算所有参数的载荷数据长度, 因为参数载荷数据可能会被压缩 98 // 导致了长度不一致的情况 99 msg.payloads.Reset() 100 // 剩余的数据是载荷数据 101 msg.payloads.Append(p) 102 return nil 103 } 104 105 // Marshal 根据Msg Header编码出对应的字节Slice 106 // *[]byte是为了提供更好的内存复用语义 107 func Marshal(msg *Message, p *container.Slice[byte]) error { 108 if err := MarshaToMux(msg, p); err != nil { 109 return err 110 } 111 integerBuffer := make([]byte, 4) 112 if len(msg.serviceName) > math.MaxUint8 { 113 return errors.New(fmt.Sprintf("serviceName max Length = 255, but now Length = %d", len(msg.serviceName))) 114 } 115 p.AppendS(byte(len(msg.serviceName))) 116 *p = append(*p, msg.serviceName...) 117 // 序列化元数据 118 if msg.MetaData.Len() > math.MaxUint8 { 119 return errors.New(fmt.Sprintf("metaData max Length = 255, but now Length = %d", msg.MetaData.Len())) 120 } 121 p.AppendS(byte(msg.MetaData.Len())) 122 msg.MetaData.Range(func(k, v string) bool { 123 binary.BigEndian.PutUint32(integerBuffer, uint32(len(k))) 124 p.Append(integerBuffer) 125 binary.BigEndian.PutUint32(integerBuffer, uint32(len(v))) 126 p.Append(integerBuffer) 127 p.Append(convert.StringToBytes(k)) 128 p.Append(convert.StringToBytes(v)) 129 return true 130 }) 131 // 序列化载荷数据描述信息 132 if msg.payloadLayout.Len() > math.MaxUint8 { 133 return errors.New(fmt.Sprintf("payloadLayout max Length = 255, but now Length = %d", msg.payloadLayout.Len())) 134 } 135 p.AppendS(byte(msg.payloadLayout.Len())) 136 for _, v := range msg.payloadLayout { 137 binary.BigEndian.PutUint32(integerBuffer, v) 138 p.Append(integerBuffer) 139 } 140 p.Append(msg.payloads) 141 return nil 142 } 143 144 // ResetMsg 指定策略的复用,对内存重用更加友好 145 // resetOther指示是否释放|Scope|NameLayout|InstanceName|MethodName|MsgId|Timestamp 146 // freeMetaData指示是否要释放存放元数据对应的map[string]sting 147 // usePayload指示是否要复用载荷数据 148 // useSize指示复用的slice类型长度的上限,即使指定了usePayload 149 // payload数据超过这个长度还是会被释放 150 func ResetMsg(msg *Message, resetOther, freeMetaData, usePayload bool, useSize int) { 151 if freeMetaData { 152 msg.MetaData.Reset() 153 } 154 if len(msg.payloadLayout) > useSize { 155 msg.payloadLayout = nil 156 } else { 157 msg.payloadLayout.Reset() 158 } 159 if !usePayload { 160 msg.payloads = nil 161 } else if usePayload && len(msg.payloads) > useSize { 162 msg.payloads = nil 163 } else { 164 msg.payloads.Reset() 165 } 166 if resetOther { 167 msg.scope = [...]uint8{MagicNumber, 0} 168 msg.serviceName = "" 169 msg.msgId = 0 170 msg.payloadLength = 0 171 } 172 }